# 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>` and pass it to `initTRPC.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 `/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().create({ transformer })`) and on the client (`createTRPCClient({ 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()` 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