Skip to main content
oRPC provides two plugins for working with HTTP headers inside procedures without breaking the transport-agnostic design.

ResponseHeadersPlugin

Injects a Headers instance (named resHeaders) into the context. Any headers written to it are merged into the final HTTP response.

Setup

import { RPCHandler } from '@orpc/server/node'
import { ResponseHeadersPlugin } from '@orpc/server/plugins'
import { router } from './router'

const handler = new RPCHandler(router, {
  plugins: [new ResponseHeadersPlugin()],
})
Then declare the expected context shape:
import { os } from '@orpc/server'
import type { ResponseHeadersPluginContext } from '@orpc/server/plugins'

// ResponseHeadersPluginContext = { resHeaders?: Headers }
const base = os.$context<ResponseHeadersPluginContext>()

Using in procedures

const procedure = base
  .handler(async ({ context }) => {
    context.resHeaders?.set('x-custom-header', 'my-value')
    context.resHeaders?.set('cache-control', 'public, max-age=60')
    return { ok: true }
  })

RequestHeadersPlugin

Injects a Headers instance (named reqHeaders) into the context, providing read access to the incoming request headers.

Setup

import { RPCHandler } from '@orpc/server/node'
import { RequestHeadersPlugin } from '@orpc/server/plugins'
import { router } from './router'

const handler = new RPCHandler(router, {
  plugins: [new RequestHeadersPlugin()],
})
import type { RequestHeadersPluginContext } from '@orpc/server/plugins'

// RequestHeadersPluginContext = { reqHeaders?: Headers }
const base = os.$context<RequestHeadersPluginContext>()

Using in procedures

const procedure = base
  .handler(async ({ context }) => {
    const userAgent = context.reqHeaders?.get('user-agent')
    return { userAgent }
  })

Using both together

import type { RequestHeadersPluginContext, ResponseHeadersPluginContext } from '@orpc/server/plugins'

const base = os.$context<
  RequestHeadersPluginContext & ResponseHeadersPluginContext
>()

const procedure = base.handler(async ({ context }) => {
  const lang = context.reqHeaders?.get('accept-language') ?? 'en'
  context.resHeaders?.set('content-language', lang)
  return { lang }
})

Build docs developers (and LLMs) love