ANTIGRAVITY LABJP
Articles/App Development
App Development/2026-03-25Intermediate

Antigravity + tRPC: Build Type-Safe Full-Stack APIs with End-to-End Type Inference

Learn how to combine Antigravity's AI agents with tRPC to build fully type-safe APIs from server to client. Covers Zod validation, React Query integration, middleware patterns, and practical development workflows.

antigravity392tRPCTypeScript11API7full-stack3type-safety3Next.js6

What Is tRPC — and Why It Matters for TypeScript Developers

If you've ever built a full-stack TypeScript application, you know the pain of keeping types synchronized between your server and client. REST APIs require manual type definitions on both sides. GraphQL needs code generation tools to produce client types from schemas. tRPC takes a fundamentally different approach: types defined on the server automatically propagate to the client through TypeScript's built-in inference system.

The key innovation is zero code generation. There are no schema files to maintain, no codegen commands to run, and no generated artifacts to keep in sync. You define your API procedures in TypeScript, and the types flow to your client calls automatically. Antigravity's AI agents understand this architecture deeply, making them particularly effective at generating tRPC code that maintains type safety across the entire stack.

// How tRPC type inference works (conceptual overview)
// Types defined on the server automatically flow to the client
//
// Server: router.user.getById({ id: string }) => { name: string, email: string }
//    ↓ TypeScript type inference
// Client: trpc.user.getById.useQuery({ id: "123" })
//    → Return type automatically inferred as { name: string, email: string }

Setting Up a tRPC Project with Antigravity

Antigravity's AI agents can scaffold a tRPC project in seconds. Start by describing the architecture you want in the chat panel:

Create a Next.js 15 App Router + tRPC v11 + Zod project with:
- src/server/trpc.ts for router configuration
- src/server/routers/ for router definitions
- src/lib/trpc.ts for client configuration
- Zod validation on all inputs

The agent will generate a well-structured base configuration like this:

// src/server/trpc.ts — tRPC initialization
import { initTRPC, TRPCError } from "@trpc/server";
import { ZodError } from "zod";
 
const t = initTRPC.create({
  errorFormatter({ shape, error }) {
    return {
      ...shape,
      data: {
        ...shape.data,
        zodError:
          error.cause instanceof ZodError ? error.cause.flatten() : null,
      },
    };
  },
});
 
// Base router and procedure exports
export const router = t.router;
export const publicProcedure = t.procedure;
// src/server/routers/user.ts — Example user router
import { z } from "zod";
import { router, publicProcedure } from "../trpc";
 
export const userRouter = router({
  getById: publicProcedure
    .input(z.object({ id: z.string().uuid() }))
    .query(async ({ input }) => {
      // Fetch user from database (e.g., Prisma)
      const user = await db.user.findUnique({
        where: { id: input.id },
      });
      if (!user) {
        throw new TRPCError({
          code: "NOT_FOUND",
          message: "User not found",
        });
      }
      return user;
      // Expected output: { id: string, name: string, email: string, createdAt: Date }
    }),
 
  create: publicProcedure
    .input(
      z.object({
        name: z.string().min(1).max(100),
        email: z.string().email(),
      })
    )
    .mutation(async ({ input }) => {
      const newUser = await db.user.create({ data: input });
      return newUser;
      // Expected output: { id: string, name: string, email: string, createdAt: Date }
    }),
});

Zod Validation Patterns That Scale

The combination of tRPC and Zod is where type safety truly shines. When you ask Antigravity to generate validation schemas, request that they be defined as reusable shared modules — this dramatically improves maintainability as your project grows.

// src/shared/schemas/user.ts — Shared validation schemas
import { z } from "zod";
 
// Base schemas (used on both server and client)
export const createUserSchema = z.object({
  name: z
    .string()
    .min(1, "Name is required")
    .max(100, "Name must be 100 characters or less"),
  email: z
    .string()
    .email("Please enter a valid email address"),
  role: z.enum(["admin", "user", "viewer"]).default("user"),
});
 
export const updateUserSchema = createUserSchema.partial().extend({
  id: z.string().uuid(),
});
 
// Auto-export inferred types for client use
export type CreateUserInput = z.infer<typeof createUserSchema>;
export type UpdateUserInput = z.infer<typeof updateUserSchema>;

Reference these schemas directly in your tRPC router for simultaneous validation and type safety:

// src/server/routers/user.ts — Using shared schemas
import { createUserSchema, updateUserSchema } from "@/shared/schemas/user";
 
export const userRouter = router({
  create: publicProcedure
    .input(createUserSchema)  // Pass the Zod schema directly
    .mutation(async ({ input }) => {
      // input is automatically inferred as CreateUserInput
      // input.name: string, input.email: string, input.role: "admin" | "user" | "viewer"
      return await db.user.create({ data: input });
    }),
 
  update: publicProcedure
    .input(updateUserSchema)
    .mutation(async ({ input }) => {
      // input.id is required, all other fields are optional
      const { id, ...data } = input;
      return await db.user.update({ where: { id }, data });
    }),
});

A helpful prompt pattern for Antigravity: "Define Zod schemas in a shared directory so both tRPC routers and form components can import them." This produces the most maintainable code structure.

Client-Side Implementation with React Query

tRPC v11 integrates seamlessly with React Query (TanStack Query), giving you powerful caching, background refetching, and optimistic updates out of the box. Antigravity generates client components that leverage these hooks automatically.

// src/lib/trpc.ts — Client configuration
import { createTRPCReact } from "@trpc/react-query";
import type { AppRouter } from "@/server/routers/_app";
 
export const trpc = createTRPCReact<AppRouter>();
// src/components/UserList.tsx — tRPC + React Query in action
"use client";
 
import { trpc } from "@/lib/trpc";
 
export function UserList() {
  // useQuery: type-safe data fetching
  const { data: users, isLoading, error } = trpc.user.list.useQuery(
    { limit: 20, offset: 0 },
    {
      staleTime: 5 * 60 * 1000,  // Cache for 5 minutes
      retry: 2,
    }
  );
 
  // useMutation: type-safe data mutations
  const utils = trpc.useUtils();
  const createUser = trpc.user.create.useMutation({
    onSuccess: () => {
      // Invalidate and refetch user list on success
      utils.user.list.invalidate();
    },
    onError: (err) => {
      // Display Zod validation errors
      if (err.data?.zodError) {
        const fieldErrors = err.data.zodError.fieldErrors;
        console.error("Validation errors:", fieldErrors);
      }
    },
  });
 
  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
 
  return (
    <div>
      <ul>
        {users?.map((user) => (
          // user type is automatically inferred
          <li key={user.id}>{user.name} ({user.email})</li>
        ))}
      </ul>
      <button
        onClick={() =>
          createUser.mutate({
            name: "New User",
            email: "new@example.com",
          })
        }
      >
        Add User
      </button>
    </div>
  );
}
// Expected output: User list displayed with an "Add User" button that creates new entries

Error Handling and Middleware Patterns

Production applications need robust authentication and error handling. tRPC's middleware system lets you implement these concerns declaratively, and Antigravity excels at generating well-structured middleware chains.

// src/server/trpc.ts — Adding authentication middleware
import { initTRPC, TRPCError } from "@trpc/server";
import type { Context } from "./context";
 
const t = initTRPC.context<Context>().create();
 
// Authentication middleware
const isAuthed = t.middleware(({ ctx, next }) => {
  if (!ctx.session?.user) {
    throw new TRPCError({
      code: "UNAUTHORIZED",
      message: "You must be logged in to access this resource",
    });
  }
  return next({
    ctx: {
      session: ctx.session,
      user: ctx.session.user,  // user is now available in all downstream procedures
    },
  });
});
 
// Rate limiting middleware
const rateLimit = t.middleware(async ({ ctx, next, path }) => {
  const key = `ratelimit:${ctx.ip}:${path}`;
  const allowed = await checkRateLimit(key, { max: 100, window: 60 });
  if (!allowed) {
    throw new TRPCError({
      code: "TOO_MANY_REQUESTS",
      message: "Rate limit exceeded. Please try again later",
    });
  }
  return next();
});
 
export const router = t.router;
export const publicProcedure = t.procedure;
export const protectedProcedure = t.procedure.use(isAuthed);
export const rateLimitedProcedure = t.procedure.use(rateLimit);

Tell Antigravity "create an authenticated tRPC router," and it will automatically include middleware like this. Adding middleware is as simple as chaining .use() calls, so the agent can augment existing routers with minimal code changes.

Getting the Most Out of Antigravity for tRPC Development

Here are the scenarios where Antigravity's AI agents add the most value to tRPC workflows.

Automated router generation: Describe your data model, and the agent produces a complete CRUD router with Zod schemas. Try: "Create a tRPC router for a Post model with title, content, and published fields. Include cursor-based pagination for the list query."

Bulk error handling: Ask the agent to "add error handling to all queries in this router — handle NOT_FOUND and INTERNAL_SERVER_ERROR with appropriate messages," and it will update every procedure consistently.

Test generation: tRPC routers are highly testable. Request "write Vitest tests for every procedure in the userRouter," and the agent will generate tests with mock data, covering both success and error paths.

For deeper dives into ORM integration, check out Antigravity + Prisma ORM for Type-Safe Database Operations and Antigravity + Drizzle ORM. If you're evaluating tRPC against GraphQL, our GraphQL + Apollo guide provides a useful comparison point.

Wrapping Up — Type-Safe Development with tRPC and Antigravity

tRPC fundamentally solves the type synchronization problem in TypeScript full-stack development. Paired with Antigravity's AI agents, you can generate router definitions, validation schemas, and client components with full end-to-end type safety — all without writing a single line of type declaration boilerplate.

Start with a small project to experience the tRPC + Antigravity workflow firsthand. Once you feel how effortless it is to have types flow automatically from server to client, you won't want to go back to manually maintaining API type definitions.

Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

App Dev2026-04-25
Antigravity x TanStack Query v5 Production Patterns: Cache Hierarchy, Optimistic Updates, and Suspense Done Right
A field guide to building TanStack Query v5 in Antigravity without painting yourself into a corner — query-key hierarchies, optimistic updates with proper rollback, Suspense and ErrorBoundary placement, and SSR hydration in Next.js, all with production-grade code.
App Dev2026-04-15
Antigravity × Firebase Data Connect: Building Type-Safe GraphQL APIs Faster with AI
A complete implementation guide for Firebase Data Connect. From GraphQL schema design to Firebase Auth integration, Antigravity AI-assisted query generation, and production deployment—all with working code examples.
App Dev2026-05-24
Running iOS Push Notification A/B Tests Weekly With Antigravity Agent — A Self-Improving Loop For Copy, Timing, And Segments
Drawing on 12 years of indie iOS app development across wallpaper and wellness apps with over 50 million cumulative downloads, this article walks through a weekly Push Notification A/B testing loop powered by Antigravity Agent. It covers the FCM bridge, BigQuery measurement, segment design, and a real D7 retention recovery story.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →