Skip to content

Router & Options

Router owns procedure registrations and runtime configuration.

router := trpcgo.NewRouter(
trpcgo.WithBatching(true),
trpcgo.WithStrictInput(true),
trpcgo.WithValidator(validate.Struct),
)
defer router.Close()

Use the trpc package to serve a router over the tRPC HTTP protocol:

mux := http.NewServeMux()
mux.Handle("/trpc/", trpc.NewHandler(router, "/trpc"))

The base path is stripped before procedure lookup. With base path /trpc, /trpc/user.get maps to procedure user.get.

OptionDefaultBehavior
WithBatching(bool)trueEnables tRPC batch requests with ?batch=1.
WithMethodOverride(bool)falseAllows queries to be called with POST.
WithMaxBodySize(n)1 MiBLimits POST bodies and GET input query values. -1 disables the limit.
WithMaxBatchSize(n)10Limits procedures in one batch. -1 disables the limit.
WithStrictInput(bool)falseRejects unknown JSON object fields with BAD_REQUEST.

Strict input uses Go’s json.Decoder.DisallowUnknownFields. By default, unknown JSON fields are silently ignored like normal json.Unmarshal.

WithValidator runs after JSON decoding and only for struct-typed inputs.

validate := validator.New()
router := trpcgo.NewRouter(
trpcgo.WithValidator(validate.Struct),
)

validate tags do not run at runtime unless you configure this option.

OptionBehavior
WithContextCreator(fn)Derives the request context from r.Context() and *http.Request.
WithOnError(fn)Receives tRPC errors for server-side logging/observability before response formatting.
WithErrorFormatter(fn)Changes the serialized error shape sent to clients.
WithDev(bool)Adds stack traces to error responses and enables dev generation behavior.

Example context creator:

router := trpcgo.NewRouter(
trpcgo.WithContextCreator(func(ctx context.Context, r *http.Request) context.Context {
if reqID := r.Header.Get("X-Request-ID"); reqID != "" {
ctx = context.WithValue(ctx, requestIDKey, reqID)
}
return ctx
}),
)

The returned context still cancels when the original request context cancels.

OptionDefaultBehavior
WithSSEPingInterval(d)10sSends keep-alive ping events.
WithSSEMaxDuration(d)30mCloses streams with a return event after the duration. -1 means unlimited.
WithSSEReconnectAfterInactivity(d)disabledSends reconnectAfterInactivityMs in the connected event.
WithSSEMaxConnections(n)unlimitedRejects extra streams with TOO_MANY_REQUESTS.
OptionBehavior
WithTypeOutput(path)Writes generated TypeScript in dev mode.
WithZodOutput(path)Writes generated Zod schemas in dev mode.
WithZodMini(bool)Uses zod/mini functional syntax.
WithWatchPackages(patterns...)Restricts dev watcher analysis to package patterns like ./cmd/api or ./internal/....

Dev generation starts when trpc.NewHandler is constructed and WithDev(true) plus WithTypeOutput(...) are set.

Use router merging to split registrations across packages.

userRouter := trpcgo.NewRouter()
trpcgo.MustQuery(userRouter, "user.list", listUsers)
adminRouter := trpcgo.NewRouter()
trpcgo.MustMutation(adminRouter, "admin.ban", banUser)
apiRouter := trpcgo.NewRouter()
if err := apiRouter.Merge(userRouter, adminRouter); err != nil {
log.Fatal(err)
}

Merge is atomic: if any duplicate path is found, no procedures are copied. Source router options and global middleware are not copied, only procedures with their per-procedure middleware, metadata, and output hooks.

MergeRouters(...) creates a new router with default options and no global middleware.