DEV Community

Alex Spinov
Alex Spinov

Posted on

tRPC Has a Free Way to Build Type-Safe APIs Without REST or GraphQL

tRPC lets your frontend call backend functions directly with full type safety. No API schema, no code generation, no REST endpoints. Just TypeScript.

The API Problem

REST: you define endpoints, write request/response types, keep them in sync manually. Types drift. Bugs happen.

GraphQL: type-safe, but requires schema definition, code generation, resolvers, and a learning curve.

tRPC: your backend functions ARE your API. The frontend calls them with full TypeScript autocomplete.

What You Get for Free

End-to-end type safety — change a backend function → frontend TypeScript errors instantly
Zero schema definition — no OpenAPI spec, no GraphQL schema, no codegen
Tiny bundle — ~2KB client-side
Works with any framework — Next.js, Express, Fastify, Nuxt, SvelteKit
Subscriptions — real-time via WebSockets built-in

How It Works

Server (define your API):

import { initTRPC } from '@trpc/server';
import { z } from 'zod';

const t = initTRPC.create();

export const appRouter = t.router({
  getUser: t.procedure
    .input(z.object({ id: z.string() }))
    .query(async ({ input }) => {
      return await db.user.findUnique({ where: { id: input.id } });
    }),
  createUser: t.procedure
    .input(z.object({ name: z.string(), email: z.string().email() }))
    .mutation(async ({ input }) => {
      return await db.user.create({ data: input });
    }),
});

export type AppRouter = typeof appRouter;
Enter fullscreen mode Exit fullscreen mode

Client (call functions directly):

import { createTRPCClient } from '@trpc/client';
import type { AppRouter } from '../server';

const trpc = createTRPCClient<AppRouter>({ ... });

// Full autocomplete — IDE knows input types and return types
const user = await trpc.getUser.query({ id: '123' });
const newUser = await trpc.createUser.mutate({ name: 'Bob', email: 'bob@example.com' });
Enter fullscreen mode Exit fullscreen mode

Rename getUser on the server → TypeScript error on the client. Immediately. No manual sync.

With React (TanStack Query integration)

const { data, isLoading } = trpc.getUser.useQuery({ id: '123' });
Enter fullscreen mode Exit fullscreen mode

All TanStack Query features (caching, refetching, optimistic updates) work out of the box.

If your frontend and backend are both TypeScript — tRPC removes an entire category of bugs.


Need web scraping or data extraction? Check out my tools on Apify — get structured data from any website in minutes.

Custom solution? Email spinov001@gmail.com — quote in 2 hours.

Top comments (0)