Go on the server.
tRPC on the client.
trpcgo keeps your API server in Go and gives frontend teams typed tRPC calls, generated AppRouter contracts, Zod schemas, and runtime enum values.
go get github.com/befabri/trpcgo@latest server.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 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.
Built on plain Go (Golang) and net/http. No TypeScript server
required.
- 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
-
TypeScript
AppRoutercontracts, Zod schemas, runtime enums, and watch mode.
Start with your Go module.
Point the router at the files you want, register your Go procedures, and the TypeScript client code is written for you.
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"),
)
trpcgo.MustMutation(router, "user.create", createUser) Open the quick start →