Go on the server.
tRPC on the client.
Write your handlers in Go and call them from TypeScript with tRPC. trpcgo generates the router types, Zod schemas, and enum values from your Go code.
Install
go get github.com/befabri/trpcgo@latestserver.go
// Role is a user's permission level.
type Role string
const (
RoleAdmin Role = "admin"
RoleEditor Role = "editor"
)
type CreateUserInput struct {
Name string `json:"name"`
Email string `json:"email" validate:"email"`
Role Role `json:"role"`
}
trpcgo.MustMutation(
router, "user.create", createUser,
)gen/
/** Role is a user's permission level. */
export type Role = "admin" | "editor";
export interface CreateUserInput {
name: string;
email: string;
role: Role;
}
type AppRouterRecord = {
user: {
create: $Mutation<CreateUserInput, User>;
};
};import { z } from "zod";
export const RoleSchema = z
.enum(["admin", "editor"])
.meta({ id: "Role" });
export const CreateUserInputSchema = z.object({
name: z.string(),
email: z.email(),
role: z.enum(["admin", "editor"]),
}).meta({ id: "CreateUserInput" });/** Role is a user's permission level. */
export const RoleEnum = {
admin: "admin",
editor: "editor",
} as const;client.ts
import { createTRPCClient, httpBatchLink } from "@trpc/client";
import type { AppRouter } from "./gen/trpc";
import { RoleEnum } from "./gen/enums";
import {
CreateUserInputSchema,
} from "./gen/zod";
const client = createTRPCClient<AppRouter>({
links: [httpBatchLink({ url: "/trpc" })],
});
const input = CreateUserInputSchema.parse({
name: "Ada",
email: "ada@example.com",
role: RoleEnum.admin,
});
const user = await
client.user.create.mutate(input);The tRPC backend features you expect, in Go.
Use net/http with the Go router and middleware you already know.
- Typed procedures
- Go queries, mutations, and SSE subscriptions, with middleware, metadata, and server-side callers.
- HTTP runtime
- Batching, SSE subscriptions, CORS, trusted origins, and error formatting.
- Frontend generation
- Generate TypeScript
AppRoutertypes, Zod schemas, and enum values. Watch mode keeps them up to date as you edit Go files.
Start with your Go module.
Register your Go procedures and choose where the generated files go. Create the HTTP handler to start generation in development mode.
router := trpcgo.NewRouter(
trpcgo.WithDev(true),
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.MustMutation(router, "user.create", createUser)Open the quick start →