Skip to content

Go Backend for tRPC TypeScript Clients

trpcgo keeps your API server in Go and gives frontend teams typed tRPC calls, generated AppRouter contracts, Zod schemas, and runtime enum values. Your Go handlers and structs are the source of truth. trpcgo serves them over the tRPC HTTP protocol so @trpc/client, @trpc/react-query, and @trpc/tanstack-react-query can consume them without a TypeScript API server.

Go source of truth

Register typed Go queries, mutations, and SSE subscriptions from your handlers and structs.

TypeScript tRPC clients

Generate an AppRouter contract that plugs into the existing tRPC client ecosystem.

Validation schemas

Generate Zod input schemas from Go validate tags for client-side form validation.

Plain HTTP runtime

Serve procedures from a net/http handler with batching, SSE, middleware, and error formatting.

Source analysis

Use trpcgo generate to preserve comments, const unions, runtime enum values, aliases, generics, and validation metadata.

Dev watch

In dev mode, regenerate frontend files on Go file changes without restarting the server.

Register procedures in Go, generate the TypeScript router type, then call the API from the same tRPC clients you already use.

router := trpcgo.NewRouter(
trpcgo.WithValidator(validate.Struct),
trpcgo.WithTypeOutput("../web/gen/trpc.ts"),
trpcgo.WithZodOutput("../web/gen/zod.ts"),
trpcgo.WithEnumsOutput("../web/gen/enums.ts"),
)
defer router.Close()
trpcgo.MustQuery(router, "user.get", getUser)
trpcgo.MustMutation(router, "user.create", createUser)
mux := http.NewServeMux()
mux.Handle("/trpc/", trpc.NewHandler(router, "/trpc"))
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from './gen/trpc.js';
const client = createTRPCClient<AppRouter>({
links: [httpBatchLink({ url: '/trpc' })],
});
const user = await client.user.get.query({ id: '1' });

Read Core Concepts to understand the runtime model, then follow Quick Start to build the first endpoint.