Integrating tRPC with SvelteKit

With the release of tRPC 11 and its resolver function now based on the Fetch API, integrating type-safe APIs into SvelteKit applications has never been easier. This post will walk you through the step-by-step process of setting up tRPC with SvelteKit. Installation Start off by creating a SvelteKit project using the Svelte CLI: npx sv create my-app You'll be prompted with a few configuration questions: For the template, choose 'SvelteKit minimal' For type checking with TypeScript, select 'Yes' Configure additional options as needed for your project Next, navigate to your newly created app and install the necessary dependencies for tRPC. cd my-app npm install @trpc/server @trpc/client zod Defining a Backend Router With the project set up and dependencies installed, let's build a typesafe API with tRPC. First, create a file at src/lib/server/trpc/init.ts: import { initTRPC } from '@trpc/server';   const t = initTRPC.create();   export const router = t.router; export const publicProcedure = t.procedure; Next, create a file at src/lib/server/trpc/router.ts and initialize a basic router: import { z } from 'zod'; import { router, publicProcedure } from './init.js'; export const appRouter = router({ hello: publicProcedure .input(z.object({ text: z.string() })) .query(({ input }) => { return { greeting: `hello ${input.text}` }; }), }); export type AppRouter = typeof appRouter; Creating the Server Endpoint Now that we've defined a router, we need to expose it through a SvelteKit endpoint. We'll use the Fetch adapter since SvelteKit is built on top of Web APIs. Create a catch-all route file at src/routes/api/trpc/[...trpc]/+server.ts: import type { RequestHandler } from './$types'; import { fetchRequestHandler } from '@trpc/server/adapters/fetch'; import { appRouter } from '$lib/server/trpc/router'; export const GET: RequestHandler = ({ request }) => { return fetchRequestHandler({ endpoint: '/api/trpc', req: request, router: appRouter, createContext() { return {}; } }); }; export const POST: RequestHandler = GET; Setting Up the Client Now let's harness the power of end-to-end type safety. Create a file at src/lib/trpc.ts: import { createTRPCClient, httpBatchLink } from '@trpc/client'; import { browser } from '$app/environment'; import { page } from '$app/state'; import type { AppRouter } from './server/trpc/router.js'; export function createTRPC() { return createTRPCClient({ links: [ httpBatchLink({ // We use the absolute path on the server url: browser ? '/api/trpc' : `${page.url.origin}/api/trpc` }) ] }); } Using Your Type-Safe API in Components We can now make API requests inside our components using the createTRPC() function: import { createTRPC } from '$lib/trpc.svelte.js'; const trpc = createTRPC(); let greeting = $state('') // Runs on server and client trpc.hello.query({ text: 'World' }).then((data) => { greeting = data.greeting; }); {greeting} Conclusion tRPC 11's Fetch API-based architecture makes it remarkably simple to integrate with SvelteKit. With just a few files, you can build a fully type-safe API that works seamlessly across your entire application. This is all you need to get started with tRPC and SvelteKit. Happy hacking!

Mar 29, 2025 - 09:52
 0
Integrating tRPC with SvelteKit

With the release of tRPC 11 and its resolver function now based on the Fetch API, integrating type-safe APIs into SvelteKit applications has never been easier. This post will walk you through the step-by-step process of setting up tRPC with SvelteKit.

Installation

Start off by creating a SvelteKit project using the Svelte CLI:

npx sv create my-app

You'll be prompted with a few configuration questions:

  • For the template, choose 'SvelteKit minimal'
  • For type checking with TypeScript, select 'Yes'
  • Configure additional options as needed for your project

Next, navigate to your newly created app and install the necessary dependencies for tRPC.

cd my-app
npm install @trpc/server @trpc/client zod

Defining a Backend Router

With the project set up and dependencies installed, let's build a typesafe API with tRPC.

First, create a file at src/lib/server/trpc/init.ts:

import { initTRPC } from '@trpc/server';
 
const t = initTRPC.create();
 
export const router = t.router;
export const publicProcedure = t.procedure;

Next, create a file at src/lib/server/trpc/router.ts and initialize a basic router:

import { z } from 'zod';
import { router, publicProcedure } from './init.js';

export const appRouter = router({
  hello: publicProcedure
    .input(z.object({ text: z.string() }))
    .query(({ input }) => {
      return { greeting: `hello ${input.text}` };
    }),
});

export type AppRouter = typeof appRouter;

Creating the Server Endpoint

Now that we've defined a router, we need to expose it through a SvelteKit endpoint. We'll use the Fetch adapter since SvelteKit is built on top of Web APIs.

Create a catch-all route file at src/routes/api/trpc/[...trpc]/+server.ts:

import type { RequestHandler } from './$types';
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { appRouter } from '$lib/server/trpc/router';

export const GET: RequestHandler = ({ request }) => {
    return fetchRequestHandler({
        endpoint: '/api/trpc',
        req: request,
        router: appRouter,
        createContext() {
            return {};
        }
    });
};

export const POST: RequestHandler = GET;

Setting Up the Client

Now let's harness the power of end-to-end type safety. Create a file at src/lib/trpc.ts:

import { createTRPCClient, httpBatchLink } from '@trpc/client';
import { browser } from '$app/environment';
import { page } from '$app/state';
import type { AppRouter } from './server/trpc/router.js';

export function createTRPC() {
    return createTRPCClient<AppRouter>({
        links: [
            httpBatchLink({
              // We use the absolute path on the server
                url: browser ? '/api/trpc' : `${page.url.origin}/api/trpc`
            })
        ]
    });
}

Using Your Type-Safe API in Components

We can now make API requests inside our components using the createTRPC() function:

<script lang="ts">
    import { createTRPC } from '$lib/trpc.svelte.js';

    const trpc = createTRPC();
    let greeting = $state('')

    // Runs on server and client
    trpc.hello.query({ text: 'World' }).then((data) => {
       greeting = data.greeting;
    });
</script>

<h1>{greeting}</h1>

Conclusion

tRPC 11's Fetch API-based architecture makes it remarkably simple to integrate with SvelteKit. With just a few files, you can build a fully type-safe API that works seamlessly across your entire application.

This is all you need to get started with tRPC and SvelteKit. Happy hacking!