Skip to content
You are reading the v2 docs, currently in beta.V1 docs
oRPC
Esc
↑↓navigate↵open⌘Jpreview
On this page

Dedupe Plugin

Prevent redundant requests by deduplicating similar in-flight requests, reducing the number of requests sent to the server.

Overview

import { DedupeLinkPlugin } from '@orpc/client/plugins'

const link = new RPCLink({
  plugins: [
    new DedupeLinkPlugin({
      groups: [
        {
          condition: () => true,
          context: {}, // Context used for the rest of the request lifecycle
        },
      ],
    }),
  ],
})

Filter

By default, the plugin deduplicates GET and QUERY requests. You can customize this behavior by providing a filter function.

const link = new RPCLink({
  plugins: [
    new DedupeLinkPlugin({
      filter: ({ request }) => request.method === 'GET',
      groups: [
        {
          condition: () => true,
          context: {},
        },
      ],
    }),
  ],
})

Groups

Only requests in the same group are deduplicated together. Each group also defines a context, as described in client context.

The following example deduplicates requests by cache policy:

interface ClientContext {
  cache?: RequestCache
}

const link = new RPCLink<ClientContext>({
  method: ({ context }) => {
    if (context?.cache) {
      return 'GET'
    }

    return 'POST'
  },
  plugins: [
    new DedupeLinkPlugin({
      groups: [
        {
          condition: ({ context }) => context?.cache === 'force-cache',
          context: { // used for the rest of the request lifecycle
            cache: 'force-cache',
          },
        },
        { // Fallback for all other requests. Keep this last.
          condition: () => true,
          context: {},
        },
      ],
    }),
  ],
  fetch: (url, init, { context }) => globalThis.fetch(url, {
    ...init,
    cache: context?.cache,
  }),
})

Now, calls made with cache = 'force-cache' use that cache setting whether they are deduplicated or sent individually.

Wait Time

By default, only identical requests made in the same event loop tick are deduplicated. Set wait to hold requests for a number of milliseconds, so identical requests made shortly after share one response.

const link = new RPCLink({
  plugins: [
    new DedupeLinkPlugin({
      wait: 10, // ms
      groups: [
        {
          condition: () => true,
          context: {},
        },
      ],
    }),
  ],
})

The wait starts when the first request is queued, so no request waits longer than wait, even while more keep arriving.

Scope

On the server, requests from different users can be deduplicated together. If your transport reads per-request data (in fetch, origin, and so on), set scope to a value unique to the incoming request.

import { AsyncLocalStorage } from 'node:async_hooks'

const requestStorage = new AsyncLocalStorage<Request>() // set per incoming request

const link = new RPCLink({
  plugins: [
    new DedupeLinkPlugin({
      scope: () => requestStorage.getStore(),
      groups: [
        {
          condition: () => true,
          context: {},
        },
      ],
    }),
  ],
})

Learn More

For implementation details, see the source code.

Last updated on October 4, 2026

Was this page helpful?