Router context

Learn how to use the router context in your app.

Built-in context

The router context is a shared object that is available to all procedures.

It contains the following properties:

  • ctx.session - The current session, if available.
  • ctx.db - The Drizzle database instance.
  • ctx.adapters - Adapters for interacting with external services.
  • ctx.logger - A logger instance.

Session

The session object contains information about the current user. It's signature depends on the used authentication provider and extends this base interface.

export interface Session {
user: {
id: string
email?: string
name?: string
}
}

Database

The Drizzle instance is available on ctx.db and can be used to interact with the database.

It's recommended to use services to interact with the database and keep the API layer thin.

Adapters

Adapters are used to interact with external services in a standardized way.

ctx.adapters.billing - The billing adapter, currently only Stripe is supported.

Logger

The logger instance is available on ctx.logger and can be used to log messages.

This wraps console.log by default, but you can drop in your own logger, like pino.

// Log a message
ctx.logger.info('Hello world')
// Error, will be shown in the console
ctx.logger.error('Something went wrong')
// Debug, only shown when `debug` is enabled
ctx.logger.debug('Hello world')

Extending the context

You can extend the context by adding your own properties in the createTRPCContext helper function.

Edit packages/api/trpc/context.ts and add your own properties:

//...
export const createTRPCContext = async <
TSession extends Session = Session,
Adapters extends ApiAdapters = ApiAdapters,
>(opts: {
headers: Headers
session: TSession | null
adapters: Adapters
debug?: boolean
}) => {
const { session, adapters, debug } = opts
const logger = {
info: console.log,
error: console.error,
debug: (...args: any[]) => {
if (debug) {
console.log(...args)
}
},
}
if (debug) {
const source = opts.headers.get('x-trpc-source') ?? 'unknown'
console.log('>>> tRPC Request from', source, 'by', session?.user)
}
return {
session,
db,
adapters,
logger,
// Add your own properties here
myCustomProperty: 'Hello world',
}
}

You can now access ctx.myCustomProperty in your procedures. Types are automatically inferred.

//...
publicProcedure.mutation(async ({ ctx, input }) => {
console.log(ctx.myCustomProperty)
}),

Was this helpful?