Skip to content

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:

ts
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:

ts
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.

ts
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:

ts
const base = os.$config({ dedupeLeadingMiddlewares: false })

WARNING

The deduplication behavior is safe unless you want to apply middleware multiple times.

Released under the MIT License.