Vibekit

tRPC API Layer

Build type-safe API procedures with tRPC 11 and TanStack Query.

The API router lives in packages/api/trpc/router.ts. It exposes auth, billing, team, notifications, ai, uploads, feedback, changelog and admin domains. Input and output types are exported as ApiInput and ApiOutput.

Add a procedure

Use the guards from packages/api/trpc/base.ts: publicProcedure allows public access, protectedProcedure requires authentication, and adminProcedure also requires the admin role. Team resources need an additional membership or owner check through ctx.abilities.

For example, add packages/api/modules/auth/procedures/update-display-name.ts:

import { db } from "database";
import { z } from "zod";
import { protectedProcedure } from "../../../trpc/base";

export const updateDisplayName = protectedProcedure
  .input(z.object({ name: z.string().min(1) }))
  .mutation(({ input, ctx }) =>
    db.user.update({
      where: { id: ctx.user.id },
      data: { name: input.name },
      select: { id: true, name: true },
    }),
  );

Export it from that directory's index.ts so the existing router registers it. Import db from database; the request context does not expose ctx.db.

Call an existing procedure

Client components use the existing provider and typed client:

"use client";

import { apiClient } from "@shared/lib/api-client";

export function UpdateNameButton() {
  const update = apiClient.auth.update.useMutation();
  return (
    <button onClick={() => update.mutate({ name: "Alex" })}>
      Update name
    </button>
  );
}

Production forms should handle pending/error states, translate labels and refresh affected user data, as the existing settings forms do. Server consumers use the caller in packages/api/trpc/caller.ts.

See Routing & Pages.

On this page