Core Concepts
trpcgo connects your Go handlers to a typed TypeScript client. You register procedures on a router, serve them over HTTP, and generate TypeScript types and optional Zod schemas from your Go code.
Router
Section titled “Router”Router owns registered procedures, global middleware, router options, output hooks, and the optional development file watcher.
Create a router for the procedures you want to serve:
router := trpcgo.NewRouter( trpcgo.WithBatching(true), trpcgo.WithStrictInput(true), trpcgo.WithValidator(validate.Struct),)defer router.Close()Register all procedures and middleware before constructing the HTTP handler. trpc.NewHandler(router, "/trpc") snapshots the current procedure map, so later registrations do not affect that handler.
Procedures
Section titled “Procedures”A procedure is a typed Go function registered at a string path:
trpcgo.MustQuery(router, "user.get", getUser)trpcgo.MustMutation(router, "user.create", createUser)trpcgo.MustVoidSubscribe(router, "user.onCreated", onUserCreated)The path becomes the tRPC procedure name. Dot-separated paths become nested TypeScript client properties, so "user.get" becomes client.user.get.query(...).
trpcgo supports:
- Queries for reads.
- Mutations for writes.
- Subscriptions for server-sent event streams.
- Void variants for procedures with no input.
Must*variants for startup code where duplicate paths are programmer errors.
HTTP Handler
Section titled “HTTP Handler”Package github.com/befabri/trpcgo/trpc exposes the tRPC-compatible HTTP handler:
mux.Handle("/trpc/", trpc.NewHandler(router, "/trpc"))If the base path is /trpc, a request to /trpc/user.get resolves to procedure user.get.
The handler supports:
GETqueries with?input=<json>.POSTmutations with a JSON body.- Optional query-over-POST when
WithMethodOverride(true)is set. - JSON batch requests with
?batch=1. - JSONL batch streaming with
trpc-accept: application/jsonl. - SSE subscriptions using
text/event-stream.
Middleware And Context
Section titled “Middleware And Context”Middleware receives decoded input after any configured input validation. Global middleware runs before per-procedure middleware.
router.Use(requestTimer)
trpcgo.MustMutation(router, "user.create", createUser, trpcgo.Use(requireAuth), trpcgo.WithMeta(map[string]string{"action": "write"}),)Inside middleware or handlers, use GetProcedureMeta(ctx) to read the active path, procedure type, and custom metadata.
Use WithContextCreator to build the request context from *http.Request, for example to attach authentication claims or request IDs.
Generation Paths
Section titled “Generation Paths”There are two ways to generate TypeScript:
- Static analysis:
go tool trpcgo generatereads Go source withgo/packages. Use it for production builds to include comments, aliases, constant unions, validation tags, and typed output parsers. - Runtime reflection:
router.GenerateTS(...)androuter.GenerateZod(...)read registered procedure reflection types. They are useful at startup but cannot see source-only metadata like Go doc comments.
In development, WithDev(true) plus WithTypeOutput(...) starts a source-analysis watcher when the HTTP handler is constructed. It generates once from source, then updates generated files on Go file changes if the source still type-checks.
Source Of Truth
Section titled “Source Of Truth”Go types define the API contract:
type CreateUserInput struct { Name string `json:"name" validate:"required,min=1,max=100"` Email string `json:"email" validate:"required,email"`}trpcgo uses those types for request decoding, optional server-side validation, TypeScript generation, and optional Zod generation. The generated frontend types should be treated as build artifacts, not hand-edited source.