DEV Community

Atlas Whoff
Atlas Whoff

Posted on

tRPC vs REST vs GraphQL in 2026: A SaaS Builder's Honest Take

Every new SaaS faces the same fork: pick an API paradigm, build on it for years. I've shipped production apps with all three in the last 18 months. Here's what actually matters when you're building alone or with a small team.

The Quick Answer

  • tRPC: Best for TypeScript monorepos, solo founders, internal APIs
  • REST: Best for public APIs, third-party integrations, multi-client
  • GraphQL: Best for complex data graphs, mobile apps, large teams with dedicated API layer

If you're a solo founder building a Next.js SaaS in 2026: tRPC. The DX advantage is too large to ignore.

tRPC: End-to-End Types Without the Schema

// server/router.ts
import { router, publicProcedure, protectedProcedure } from './trpc';
import { z } from 'zod/v4';

export const appRouter = router({
  user: router({
    getById: protectedProcedure
      .input(z.object({ id: z.string().uuid() }))
      .query(async ({ input, ctx }) => {
        return ctx.db.user.findUniqueOrThrow({ where: { id: input.id } });
      }),

    update: protectedProcedure
      .input(z.object({
        id: z.string().uuid(),
        name: z.string().min(1).max(100),
        email: z.email(),
      }))
      .mutation(async ({ input, ctx }) => {
        return ctx.db.user.update({
          where: { id: input.id },
          data: { name: input.name, email: input.email },
        });
      }),
  }),
});

export type AppRouter = typeof appRouter;
Enter fullscreen mode Exit fullscreen mode
// client — zero code generation, full type safety
import { trpc } from '../utils/trpc';

function UserProfile({ userId }: { userId: string }) {
  // Return type inferred automatically from the router definition
  const { data: user } = trpc.user.getById.useQuery({ id: userId });
  const updateUser = trpc.user.update.useMutation();

  // user.name, user.email — fully typed, no codegen step
}
Enter fullscreen mode Exit fullscreen mode

What you don't have to do:

  • Write an OpenAPI spec
  • Run a codegen step
  • Maintain a separate client SDK
  • Write fetch wrappers

Refactor the server: TypeScript errors appear on the client immediately. This is the tRPC advantage in one sentence.

The ceiling: tRPC only works when client and server share a TypeScript codebase. The moment you need a mobile app, a third-party integration, or a Python service calling your API — you need REST or a separate REST layer.

REST: Still the Right Answer for Public APIs

// Next.js App Router API route
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod/v4';

const CreateUserSchema = z.object({
  name: z.string().min(1),
  email: z.email(),
  plan: z.enum(['free', 'pro', 'enterprise']),
});

export async function POST(req: NextRequest) {
  const body = await req.json();
  const parsed = CreateUserSchema.safeParse(body);

  if (!parsed.success) {
    return NextResponse.json(
      { error: 'Validation failed', details: parsed.error.issues },
      { status: 400 }
    );
  }

  const user = await db.user.create({ data: parsed.data });
  return NextResponse.json(user, { status: 201 });
}
Enter fullscreen mode Exit fullscreen mode

REST's strengths in 2026:

  • Works with any client in any language
  • HTTP caching (CDN, browser) works naturally
  • OpenAPI + codegen gives typed clients for other teams
  • Every debugging tool understands HTTP

REST's weakness for solo SaaS: you're writing a lot of boilerplate that tRPC would eliminate, and TypeScript errors don't propagate client-server automatically.

GraphQL: When the Data Graph Justifies the Complexity

// schema.graphql
type Query {
  user(id: ID!): User
  users(filter: UserFilter): [User!]!
}

type User {
  id: ID!
  name: String!
  email: String!
  orders(limit: Int): [Order!]!
  subscription: Subscription
}

type Order {
  id: ID!
  total: Int!
  items: [OrderItem!]!
}
Enter fullscreen mode Exit fullscreen mode

Clients fetch exactly what they need:

# Mobile app — minimal fields
query GetUserCard {
  user(id: "usr_123") {
    name
    subscription { plan }
  }
}

# Dashboard — full data
query GetUserDetail {
  user(id: "usr_123") {
    name
    email
    orders(limit: 10) {
      id
      total
      items { name quantity }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Same endpoint, different responses. No over-fetching.

GraphQL is the right choice when:

  • You have 3+ client types (web, iOS, Android) with different data needs
  • Your data has deep relationships (social graphs, content DAGs)
  • You have a dedicated backend team that can own the schema
  • You're building a developer-facing platform where query flexibility matters

GraphQL is overkill when:

  • It's a solo project with one web client
  • Your data is mostly flat CRUD
  • You don't have time to configure a resolver layer, caching strategy, and N+1 query prevention

Real-World Performance: What Matters at SaaS Scale

Request overhead (rough benchmarks, similar query complexity):
tRPC:     ~0.1ms (function call, same process in monorepo)
REST:     ~1-3ms (HTTP parsing overhead, simpler serialization)
GraphQL:  ~3-10ms (resolver tree, field resolution, N+1 if unguarded)
Enter fullscreen mode Exit fullscreen mode

At SaaS scale, these differences are irrelevant compared to database query time. Don't optimize API protocol — optimize queries.

The Pattern I Use in 2026

Internal API (Next.js ↔ own frontend):  tRPC
Public API (third-party devs):          REST + OpenAPI
Webhooks (Stripe, GitHub, etc.):        REST endpoints
LLM tool calls:                         REST (Claude/OpenAI expect JSON schemas)
Enter fullscreen mode Exit fullscreen mode

tRPC handles 90% of the surface area with 10% of the code. REST handles the edges where tRPC doesn't reach.

Migration Risk

One thing nobody talks about: switching API paradigms is expensive. Choose with a 2-year horizon.

tRPC → REST: doable (it's just HTTP underneath), but you lose type propagation
REST → GraphQL: significant — resolver layer, schema design, client query refactoring
GraphQL → REST: usually a sign something went wrong in selection


Ship Your API Faster

The AI SaaS Starter Kit ($99) ships with tRPC pre-configured alongside Next.js App Router — auth middleware, Zod validation, and Drizzle ORM wired up end-to-end. Skip the 2-day setup.

Building automations that need to call your API? The Workflow Automator MCP ($15/mo) integrates with REST and tRPC backends so your AI workflows are as type-safe as your app.


If I were starting a SaaS today with one developer: tRPC, Next.js App Router, Drizzle, Supabase. That stack gets you to $10k MRR without touching API design again.

What stack are you shipping on in 2026?

Top comments (0)