tRPC-SvelteKit v4.1.0

End-to-end typesafe APIs for your SvelteKit applications

LLMs.txt

If you're using AI assistants or coding agents (such as Claude, ChatGPT, Cursor or GitHub Copilot) to build your application, you can point them to the tRPC-SvelteKit documentation in a format they can easily read, following the LLMs.txt standard.

Two files are generated from this website's content every time it's published:

  • llms.txt - a concise overview: the most important facts about using tRPC-SvelteKit, followed by links to every documentation page and example app;
  • llms-full.txt - the complete documentation in a single file, including all the code examples shown on this website.

How to use them

  • Paste https://icflorescu.github.io/trpc-sveltekit/llms-full.txt in a chat with your AI assistant and ask it to read the file before answering your questions;
  • Add https://icflorescu.github.io/trpc-sveltekit/llms.txt as a documentation source in your AI-powered editor (for instance, with the @Docs feature in Cursor);
  • Tell your coding agent to fetch https://icflorescu.github.io/trpc-sveltekit/llms-full.txt, or download the file and reference it from your project's agent instructions (CLAUDE.md, AGENTS.md, .cursor/rules etc.).

Use llms-full.txt when your tool can handle a larger context and you want the most accurate answers; use llms.txt when your tool can follow links and fetch only the pages it needs.

What's inside llms.txt

llms.txt
# tRPC-SvelteKit

> tRPC-SvelteKit is a tRPC adapter that makes it easy to build end-to-end typesafe APIs for your SvelteKit applications. It provides a single SvelteKit `handle` hook that serves your tRPC router over HTTP and works with every SvelteKit adapter (Node, Bun, Vercel, Netlify, Cloudflare, …), a `createTRPCClient` function to call your procedures from pages and `load` functions, typed TanStack Svelte Query options and query keys (`createTRPCQueryOptions`), support for setting cookies and headers from procedures, streamed responses and subscriptions over server-sent events, and experimental WebSocket support for `@sveltejs/adapter-node`.

Key facts:

- `trpc-sveltekit` v4 (current version: 4.1.0) requires tRPC v11 (`@trpc/server` and `@trpc/client` `^11.0.0`) and works with SvelteKit 2 or 3 (`@sveltejs/kit` `^2.0.0 || ^3.0.0`) on Node.js `>=20`. Install it with `pnpm add trpc-sveltekit @trpc/server @trpc/client`. It doesn’t depend on Svelte itself; the examples use Svelte 5 with runes. Use `trpc-sveltekit@3` for tRPC v10 (SvelteKit 1 and 2) and `trpc-sveltekit@2` for tRPC v9 (SvelteKit 1).
- The main entry point (`trpc-sveltekit`) exports `createTRPCHandle`, used in your server hooks, `createTRPCClient`, used in your pages and `load` functions, and `createTRPCQueryOptions`, for TanStack Svelte Query. It also exports their types (`CreateTRPCHandleOptions`, `TRPCHandle`, `CreateTRPCClientOptions`, `TRPCClientInit`, `ValidRoute`). The experimental WebSocket APIs are exported separately, from `trpc-sveltekit/websocket`.
- `createTRPCHandle({ router, createContext })` returns a SvelteKit `handle` hook: export it as `handle` from `src/hooks.server.ts`. Don’t create a `+server.ts` endpoint (such as `src/routes/trpc/[...trpc]/+server.ts`) for tRPC. To combine it with your own hooks, use `sequence` from `@sveltejs/kit/hooks` (e.g. `export const handle = sequence(authHandle, trpcHandle)`); a hook that populates `event.locals` for your context must come before the tRPC handle. The handle also accepts the options of tRPC’s HTTP handlers (`onError`, `responseMeta`, `batching`, `allowBatching`, `allowMethodOverride`) with their tRPC v11 signatures.
- `createContext` receives the SvelteKit `RequestEvent` as its first argument (so you can read `event.cookies`, `event.locals`, `event.request.headers` …) and the tRPC fetch adapter options (`req`, `resHeaders`, `info`) as its second; it may be async. Declare the context type as `Awaited<ReturnType<typeof createContext>>` and pass it to `initTRPC.context<Context>().create()`.
- The tRPC API is served under the `/trpc` path prefix by default (procedure `authors.list` is at `/trpc/authors.list`). The prefix is reserved, so don’t put SvelteKit routes under it. Change it with the `url` option of `createTRPCHandle` (it must start with `/` and must not end with `/`), and pass the same `url` to `createTRPCClient`.
- Create clients with `createTRPCClient` from `trpc-sveltekit`, not the function of the same name from `@trpc/client` (which requires `links`). By default it uses an `httpBatchLink` pointing at `<origin>/trpc` and passes any other `httpBatchLink` option through (`transformer`, `headers`, `maxURLLength`, `methodOverride` …). You can pass your own `links` instead (then `url` and `init` aren’t accepted).
- On the server, `createTRPCClient` throws unless you pass `init`: a SvelteKit load event, or anything with a `url` and optionally a `fetch` function. With the event of a universal `load` function, the client uses SvelteKit’s `fetch`, which forwards cookies and, during server-side rendering, calls your `handle` directly instead of making an HTTP request. In the browser `init` is optional; components usually pass `page` from `$app/state`. The docs use a `trpc(init?)` helper in `src/lib/trpc/client.ts` that reuses a single client in the browser and creates a new one for each call on the server, where every request has its own `fetch`.
- Page data vs page server data: in a universal `load` function (`+page.ts`, `+layout.ts`), which runs **both** on the server and in the browser, call `await trpc(event).some.procedure.query()`. In server-only code (`+page.server.ts`, `+layout.server.ts`, form actions), skip HTTP and use a server-side caller: export `const createCaller = t.createCallerFactory(router)` next to your router, then call `await createCaller(await createContext(event)).some.procedure(input)` (procedures are called as functions, without `.query()` or `.mutate()`).
- Data transformers (such as superjson, or `trpc-transformer`, which adds Decimal.js support): in tRPC v11 they’re set on links rather than on the client. Use the same transformer on the server (`initTRPC.context<Context>().create({ transformer })`) and on the client (`createTRPCClient<Router>({ init, transformer })` forwards it to its default link; with custom `links`, set it on each link).
- Procedures can set response headers and cookies through the request event, if you put it in the context: `ctx.event.setHeaders({ … })`, `ctx.event.cookies.set(…)` and `ctx.event.cookies.delete(…)`. The handle copies them onto the tRPC response. Set cookies with `cookies`, not with `setHeaders` (SvelteKit throws on `set-cookie`). When streaming, only the headers and cookies set before the response starts are sent.
- Responses are streamed, so `httpBatchStreamLink` and subscriptions over server-sent events (`httpSubscriptionLink`, combined with `splitLink`; subscriptions can be written as async generators) work with every SvelteKit adapter. Prefer them over the experimental WebSocket support unless you need WebSockets.
- TanStack Svelte Query (v6, `createQuery(() => options)`): `createTRPCQueryOptions(client)` returns a proxy mirroring your router, e.g. `api.authors.list.queryOptions(input, { staleTime })`, `api.authors.save.mutationOptions({ onSuccess })`, `api.authors.list.queryKey(input)` and `api.authors.pathKey()` (to invalidate every query of a procedure or router). The first argument of `queryOptions` is always the input (`undefined` for procedures without input). Types come from the tRPC client, transformers included. Don’t use `trpc-svelte-query-adapter` with v4: it only supports tRPC v10 and Svelte Query v5.
- The handle doesn’t read `url.searchParams`, so it can be used in apps with prerendered pages; procedure calls made from prerendered `load` functions run at build time.
- Experimental WebSocket support (`trpc-sveltekit/websocket`) works with `@sveltejs/adapter-node` only and needs the optional `ws` peer dependency. It has four parts: the `vitePluginTrpcWebSocket` Vite plugin (or `trpcWebSocketPlugin({ path })`) for the dev and preview servers; a `wsServer.js` production entry point next to `package.json` calling `SvelteKitTRPCWSServer(import.meta.url)`, which you start the app with (`node ./wsServer.js` instead of `node build`); `createTRPCWebSocketServer({ router, createContext })` in `hooks.server.ts`, guarded with `if (!building)`; and `createTRPCWebSocketClient<Router>()` on the client. Its `createContext` receives the `CreateWSSContextFnOptions` of `@trpc/server/adapters/ws` (`{ req, res, info }`), not a SvelteKit request event: read cookies from `req.headers.cookie`, or a token from `info.connectionParams` (set with the client’s `connectionParams` option). `createTRPCWebSocketClient` returns `undefined` on the server, so only use the client in the browser (event handlers, `$effect`). All procedures go over the WebSocket unless you build your own client with a `splitLink`. On `SIGTERM`/`SIGINT`, `SvelteKitTRPCWSServer` closes the WebSocket connections so the process can exit; with a custom server, call `closeWSSGlobalInstance()` yourself.
- Upgrading from v3 (tRPC v10): v4 is mostly API-compatible. Upgrade `@trpc/server` and `@trpc/client` to v11 and follow the tRPC v11 migration guide (https://trpc.io/docs/migrate-from-v10-to-v11). `createContext` now also receives the fetch adapter options as a second argument; `responseMeta` and `onError` use the tRPC v11 signatures; `createTRPCClient` forwards `transformer` and every `httpBatchLink` option to its link; `@sveltejs/adapter-node` is no longer a peer dependency, `ws` is only needed for WebSocket support, and the `cookie` package is no longer a dependency.
- The examples use SvelteKit 3 conventions: `#lib/...` subpath imports (declared in the `imports` field of `package.json`) instead of `$lib/...`, `building` from `$app/env` and private environment variables from `$app/env/private`. In a SvelteKit 2 app, import from `$lib/...`, get `building` from `$app/environment` and private environment variables from `$env/static/private` (or `$env/dynamic/private`).

The complete documentation, including all code examples, is available as a single file at https://icflorescu.github.io/trpc-sveltekit/llms-full.txt

## Docs

- [Getting started](https://icflorescu.github.io/trpc-sveltekit/getting-started): Get started with tRPC-SvelteKit (installation, router, context, hooks, client helper, calling procedures)
- [Upgrading to v4](https://icflorescu.github.io/trpc-sveltekit/upgrading-to-v4): How to upgrade to tRPC-SvelteKit v4 and tRPC v11 (tRPC v11, changed options and dependencies)
- [Page data](https://icflorescu.github.io/trpc-sveltekit/page-data): How to load SvelteKit page data with tRPC (calling procedures in universal `+page.ts` load functions)
- [Page server data](https://icflorescu.github.io/trpc-sveltekit/page-server-data): How to load SvelteKit server data with tRPC (calling procedures in `+page.server.ts` load functions with a server-side caller)
- [Using with Svelte Query](https://icflorescu.github.io/trpc-sveltekit/using-with-svelte-query): Typed TanStack Svelte Query options and query keys for your tRPC procedures, with createTRPCQueryOptions (`createTRPCQueryOptions`: typed query and mutation options and query keys for TanStack Svelte Query, SSR prefetching, invalidation)
- [Suggested structure](https://icflorescu.github.io/trpc-sveltekit/suggested-structure): Suggested structure for a tRPC-SvelteKit application (file layout for routers, middleware and the client in larger apps)
- [Authentication](https://icflorescu.github.io/trpc-sveltekit/authentication): How to add authentication to a tRPC-SvelteKit application (cookie-based JWT authentication, context, auth middleware)
- [Handling errors](https://icflorescu.github.io/trpc-sveltekit/handling-errors): How to handle errors in a tRPC-SvelteKit application (catching `TRPCClientError` in pages, logging errors with `onError`)
- [Recipes and caveats](https://icflorescu.github.io/trpc-sveltekit/recipes-and-caveats): Recipes and caveats for tRPC-SvelteKit (client options, custom links, SSE subscriptions, response headers and cookies, data transformers, response caching, inferring types, the reserved `/trpc` prefix, prerendering)
- [WebSocket support (experimental)](https://icflorescu.github.io/trpc-sveltekit/experimental-websocket-support): Experimental WebSocket support in tRPC-SvelteKit (setup with `@sveltejs/adapter-node`, Vite plugin, production server, WebSocket client, how it works)

## Examples

- [simple](https://github.com/icflorescu/trpc-sveltekit/tree/main/examples/simple): The basics: router, context, hooks, client helper, page data, page server data and TanStack Svelte Query
- [bookstall](https://github.com/icflorescu/trpc-sveltekit/tree/main/examples/bookstall): Authentication, CRUD, error handling, data transformer, Prisma
- [websocket](https://github.com/icflorescu/trpc-sveltekit/tree/main/examples/websocket): Subscriptions over WebSockets with `@sveltejs/adapter-node` (experimental)

## Optional

- [Contribute and support](https://icflorescu.github.io/trpc-sveltekit/contribute-and-support): Contribute to tRPC-SvelteKit and support the project
- [Acknowledgements](https://icflorescu.github.io/trpc-sveltekit/acknowledgements): Huge thanks to tRPC-SvelteKit sponsors
- [Hire the author](https://icflorescu.github.io/trpc-sveltekit/hire-the-author): Hire the author of tRPC-SvelteKit
- [Changelog](https://github.com/icflorescu/trpc-sveltekit/blob/main/CHANGELOG.md): Notable changes in each tRPC-SvelteKit version
- [Source code](https://github.com/icflorescu/trpc-sveltekit): GitHub repository
- [npm package](https://www.npmjs.com/package/trpc-sveltekit): `trpc-sveltekit` on npm