Code Generation
Generation turns Go procedure registrations into the TypeScript contract consumed by tRPC clients.
Recommended Production Flow
Section titled “Recommended Production Flow”Use static analysis before building the frontend:
//go:generate go tool trpcgo generate -o ../web/gen/trpc.ts --zod ../web/gen/zod.ts ./...go generate ./...Static analysis reads source packages with go/packages, so it can preserve source-only information that reflection cannot see.
go tool trpcgo generate [flags] [packages]If no package pattern is provided, trpcgo analyzes ..
| Flag | Description |
|---|---|
-o, -output | TypeScript output file. Defaults to stdout. |
-dir | Working directory for package resolution. Defaults to .. |
-w, -watch | Watch Go files and regenerate on write/create events. |
-zod | Zod schema output file. |
-zod-mini | Emit zod/mini functional syntax. |
Examples:
go tool trpcgo generate -o web/gen/trpc.ts ./...go tool trpcgo generate -o web/gen/trpc.ts --zod web/gen/zod.ts ./...go tool trpcgo generate -o web/gen/trpc.ts --zod web/gen/zod.ts -w ./...Runtime And Dev Generation
Section titled “Runtime And Dev Generation”The router can write generated files from registered procedure reflection types:
if err := router.GenerateTS("web/gen/trpc.ts"); err != nil { return err}
if err := router.GenerateZod("web/gen/zod.ts"); err != nil { return err}In normal development, prefer the integrated watcher:
router := trpcgo.NewRouter( trpcgo.WithDev(true), trpcgo.WithTypeOutput("../web/gen/trpc.ts"), trpcgo.WithZodOutput("../web/gen/zod.ts"),)defer router.Close()When trpc.NewHandler is constructed, trpcgo starts the watcher. It generates once from source, then regenerates when .go files change. If source analysis fails because the Go code is temporarily broken, previous generated files are preserved.
Use WithWatchPackages to avoid watching unrelated frontend or generated directories in larger repositories:
trpcgo.WithWatchPackages("./cmd/api", "./internal/...")Static Analysis Vs Reflection
Section titled “Static Analysis Vs Reflection”| Feature | Static CLI | Runtime reflection |
|---|---|---|
| Registered procedure input/output types | Yes | Yes |
json, tstype, validate, ts_doc, zod_omit tags | Yes | Yes |
| Go doc comments as JSDoc | Yes | No |
| const groups as string/number unions | Yes | No |
| aliases and defined basic types | Yes | Limited |
| source-level typed output parser discovery | Yes | Registered typed parsers only |
Use the CLI for generated files committed or built in CI. Use dev watch for a fast local feedback loop.
Generated TypeScript Shape
Section titled “Generated TypeScript Shape”Generated trpc.ts includes:
// Code generated by trpcgo. DO NOT EDIT.- Type-only imports from
@trpc/server. - Exported TypeScript definitions for reachable Go types.
$Query,$Mutation, and$Subscriptionhelper aliases only when needed.- Nested
AppRouterRecordgenerated from dot-separated procedure paths. - Exported
AppRouter. RouterInputsandRouterOutputshelpers when procedures exist.
Procedure paths become nested objects:
trpcgo.MustQuery(router, "user.get", getUser)trpcgo.MustMutation(router, "admin.user.ban", banUser)type AppRouterRecord = { user: { get: $Query<GetUserInput, User>; }; admin: { user: { ban: $Mutation<BanUserInput, BanUserResult>; }; };};Type Mapping
Section titled “Type Mapping”Common Go-to-TypeScript mappings:
| Go | TypeScript |
|---|---|
string | string |
bool | boolean |
| numeric types | number |
time.Time | string |
[]T, [N]T | T[] |
[]byte | string |
map[K]V | Record<K, V> |
any, interface{} | unknown |
json.RawMessage | unknown |
json.Number | number |
TrackedEvent[T] | T |
Pointer fields and fields tagged omitempty or omitzero become optional unless overridden with tstype:",required".
Detection Rules And Limits
Section titled “Detection Rules And Limits”Static generation discovers calls to the top-level registration functions such as Query, Mutation, Subscribe, SubscribeWithFinal, and their Void/Must variants.
Important limits:
- Procedure paths must be string literals for static analysis.
- Packages must load and type-check successfully.
- Custom wrapper functions are only detected if the analyzer can see the underlying top-level registration call with a literal path.
- Zod generation targets procedure input types and their dependencies, not output-only types.
- Reflection generation cannot emit source comments or const unions.
Zod Output
Section titled “Zod Output”Pass --zod or configure WithZodOutput to generate schemas for typed procedure inputs.
go tool trpcgo generate -o web/gen/trpc.ts --zod web/gen/zod.ts ./...If no procedures have typed inputs, runtime GenerateZod and dev watch remove stale Zod files. The CLI can still create an empty file.
See Zod Schemas for validate tag mapping, zod/mini, omitempty, dive, cross-field rules, and frontend usage.