UNPKG

@trpc/server

Version:

The tRPC server library

116 lines (91 loc) • 4.71 kB
--- name: caching description: Set HTTP cache headers on tRPC query responses via the adapter's responseMeta callback (info, ctx, type, errors, eagerGeneration) for CDN and browser caching. Configure Cache-Control, s-maxage, stale-while-revalidate. Handle caching with batching, streaming and authenticated requests. Avoid caching mutations, errors, and authenticated responses. requires: - server-setup sources: - www/v11/docs/server/caching.md metadata: type: core library: trpc library_version: 11.23.0 --- <!-- Generated from www/v11/docs/server/caching.md by www/build/skills.ts. Edit the docs instead. --> # Response Caching From https://trpc.io/docs/server/caching Since all tRPC queries are normal HTTP `GET` requests, you can use standard HTTP cache headers to cache responses. This can make responses snappy, give your database a rest, and help scale your API. > [!NOTE] Info > Always be careful with caching - especially if you handle personal information. > > &nbsp; > Since batching is enabled by default, it's recommended to set your cache headers in the `responseMeta` function and make sure that there are not any concurrent calls that may include personal data - or to omit cache headers completely if there is an auth header or cookie. > > &nbsp; > You can also use a [`splitLink`](https://trpc.io/docs/client/links/splitLink) to split your public requests and those that should be private and uncached. ## Using `responseMeta` to cache responses Most tRPC adapters support a `responseMeta` callback that lets you set HTTP headers (including cache headers) based on the procedures being called. > This works with any hosting provider that supports standard HTTP cache headers (e.g. Vercel, Cloudflare, AWS CloudFront). ```ts no-check title="server.ts" import { initTRPC } from '@trpc/server'; import { createHTTPServer } from '@trpc/server/adapters/standalone'; import type { CreateHTTPContextOptions } from '@trpc/server/adapters/standalone'; export const createContext = async (opts: CreateHTTPContextOptions) => { return { req: opts.req, res: opts.res, }; }; type Context = Awaited<ReturnType<typeof createContext>>; export const t = initTRPC.context<Context>().create(); const waitFor = async (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); export const appRouter = t.router({ public: t.router({ slowQueryCached: t.procedure.query(async (opts) => { await waitFor(5000); // wait for 5s return { lastUpdated: new Date().toJSON(), }; }), }), }); // Exporting `type AppRouter` only exposes types that can be used for inference // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export export type AppRouter = typeof appRouter; // export API handler const server = createHTTPServer({ router: appRouter, createContext, responseMeta(opts) { const { info, errors, type, eagerGeneration } = opts; // assuming all your public routes are in the `public` router const allPublic = info?.calls.every((call) => call.path.startsWith('public.'), ); // checking that no procedures errored // (when streaming, headers are sent before any results are known) const allOk = !eagerGeneration && errors.length === 0; // checking we're doing a query request const isQuery = type === 'query'; if (allPublic && allOk && isQuery) { // cache request for 1 day + revalidate once every second const ONE_DAY_IN_SECONDS = 60 * 60 * 24; return { headers: new Headers([ [ 'cache-control', `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`, ], ]), }; } return {}; }, }); server.listen(3000); ``` `responseMeta` runs once per HTTP response, so with batching it decides the headers for every procedure in the batch: only cache if all of them are public. It also gets the request's `ctx`, e.g. to skip caching for signed-in users. For streamed responses, like those of [`httpBatchStreamLink`](https://trpc.io/docs/client/links/httpBatchStreamLink), the headers are sent before any procedure has finished, so `responseMeta` runs with `eagerGeneration: true` and an empty `errors` array. > [!TIP] > If you are using the deprecated Next.js Pages Router integration (`@trpc/next`), see the [Next.js SSR caching guide](https://trpc.io/docs/client/nextjs/pages-router/ssr#response-caching-with-ssr) for Next.js-specific caching examples using `createTRPCNext` and the Next.js adapter. ## Related skills - `server-setup` (https://trpc.io/docs/server/overview): `npx @tanstack/intent@latest load @trpc/server#server-setup`