tRPC on Cloudflare with SST
Create and deploy a tRPC API in Cloudflare with SST.
We are going to build a tRPC API, a simple client, and deploy it to Cloudflare using SST.
Before you get started, make sure to Create your Cloudflare API token.
1. Create a project
Let’s start by creating our app.
mkdir my-trpc-app && cd my-trpc-appnpm init -y
Init SST
Now let’s initialize SST in our app.
npx sst@latest initnpm install
Select the defaults and pick Cloudflare. This’ll create a sst.config.ts
file in your project root.
Set the Cloudflare API token
You can save your Cloudflare API token in a .env
file or just set it directly.
export CLOUDFLARE_API_TOKEN=aaaaaaaa_aaaaaaaaaaaa_aaaaaaaaexport CLOUDFLARE_DEFAULT_ACCOUNT_ID=aaaaaaaa_aaaaaaaaaaaa_aaaaaaaa
2. Add the API
Let’s add two Workers; one for our tRPC server and one that’ll be our client. Update your sst.config.ts
.
async run() { const trpc = new sst.cloudflare.Worker("Trpc", { url: true, handler: "index.ts", });
const client = new sst.cloudflare.Worker("Client", { url: true, link: [trpc], handler: "client.ts", });
return { api: trpc.url, client: client.url, };}
We are linking the server to our client. This will allow us to access the server in our client.
3. Create the server
Let’s create our tRPC server. Add the following to index.ts
.
const t = initTRPC.context().create();
const router = t.router({ greet: t.procedure .input(z.object({ name: z.string() })) .query(({ input }) => { return `Hello ${input.name}!`; }),});
export type Router = typeof router;
export default { async fetch(request: Request): Promise<Response> { return fetchRequestHandler({ router, req: request, endpoint: "/", createContext: (opts) => opts, }); },};
We are creating a simple method called greet
that takes a string as an input.
Add the relevant imports.
import { z } from "zod";import { initTRPC } from "@trpc/server";import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
And install the npm packages.
npm install zod @trpc/server@next
4. Add the client
Now we’ll connect to our server in our client. Add the following to client.ts
.
export default { async fetch() { const client = createTRPCClient<Router>({ links: [ httpBatchLink({ url: "http://localhost/", fetch(req) { return Resource.Trpc.fetch(req); }, }), ], }); return new Response( await client.greet.query({ name: "Patrick Star", }), ); },};
Add the imports. Notice we are importing the types for our API.
import { Resource } from "sst";import type { Router } from "./index";import { createTRPCClient, httpBatchLink } from "@trpc/client";
Install the client npm package.
npm install @trpc/client@next
Start dev mode
Start your app in dev mode.
npx sst dev
This will give you two URLs.
+ Complete api: https://my-trpc-app-jayair-trpcscript.sst-15d.workers.dev client: https://my-trpc-app-jayair-clientscript.sst-15d.workers.dev
Test your app
To test our app, hit the client URL.
curl https://my-trpc-app-jayair-clientscript.sst-15d.workers.dev
This will print out Hello Patrick Star!
.
5. Deploy your app
Now let’s deploy your app.
npx sst deploy --stage production
You can use any stage name here but it’s good to create a new stage for production.