Dedupe Middleware
This guide explains how to optimize your middleware for fast and efficient repeated execution.
Problem
When a procedure calls another procedure, overlapping middleware might be applied in both.
Similarly, when using .use(auth).router(router)
, some procedures inside router
might already include the auth
middleware.
WARNING
Redundant middleware execution can hurt performance, especially if the middleware is resource-intensive.
Solution
Use the context
to track middleware execution and prevent duplication. For example:
const dbProvider = os
.$context<{ db?: Awaited<ReturnType<typeof connectDb>> }>()
.middleware(async ({ context, next }) => {
/**
* If db already exists, skip the connection.
*/
const db = context.db ?? await connectDb()
return next({ context: { db } })
})
Now dbProvider
middleware can be safely applied multiple times without duplicating the database connection:
const foo = os.use(dbProvider).handler(({ context }) => 'Hello World')
const bar = os.use(dbProvider).handler(({ context }) => {
/**
* Now when you call foo, the dbProvider middleware no need to connect to the database again.
*/
const result = call(foo, 'input', { context })
return 'Hello World'
})
/**
* Now even when `dbProvider` is applied multiple times, it still only connects to the database once.
*/
const router = os
.use(dbProvider)
.use(({ next }) => {
// Additional middleware logic
return next()
})
.router({
foo,
bar,
})
Built-in Dedupe Middleware
oRPC can automatically dedupe some middleware under specific conditions.
INFO
Deduplication occurs only if the router middlewares is a subset of the leading procedure middlewares and appears in the same order.
const router = os.use(logging).use(dbProvider).router({
ping: os.use(logging).use(dbProvider).use(auth).handler(({ context }) => 'ping'),
pong: os.use(logging).use(dbProvider).handler(({ context }) => 'pong'),
// ⛔ Deduplication does not occur:
diff_subset: os.use(logging).handler(({ context }) => 'ping'),
diff_order: os.use(dbProvider).use(logging).handler(({ context }) => 'pong'),
diff_leading: os.use(monitor).use(logging).use(dbProvider).handler(({ context }) => 'bar'),
})
// --- equivalent to ---
const router = {
ping: os.use(logging).use(dbProvider).use(auth).handler(({ context }) => 'ping'),
pong: os.use(logging).use(dbProvider).handler(({ context }) => 'pong'),
// ⛔ Deduplication does not occur:
diff_subset: os.use(logging).use(dbProvider).use(logging).handler(({ context }) => 'ping'),
diff_order: os.use(logging).use(dbProvider).use(dbProvider).use(logging).handler(({ context }) => 'pong'),
diff_leading: os.use(logging).use(dbProvider).use(monitor).use(logging).use(dbProvider).handler(({ context }) => 'bar'),
}
Configuration
Disable middleware deduplication by setting dedupeLeadingMiddlewares
to false
in .$config
:
const base = os.$config({ dedupeLeadingMiddlewares: false })
WARNING
The deduplication behavior is safe unless you want to apply middleware multiple times.