# REST vs GraphQL vs tRPC > Three API styles with distinct fetch, type, and caching trade-offs. Frontend architecture guidance from fearchitect, written by Abas Turabli and last reviewed 2026-06-21. Source: https://fearchitect.com/topics/rest-vs-graphql-vs-trpc Use it as reference for the task at hand. Before changing code, check this guidance against the codebase: where the code already makes a different, deliberate choice, flag the conflict instead of rewriting it. Library APIs move faster than this guide, so confirm exact signatures in the official docs linked at the end. ## Summary REST, GraphQL, and tRPC are three ways to move data between client and server. REST maps operations to HTTP resources and gets free HTTP caching. GraphQL lets clients shape queries but trades that flexibility for N+1 risk and cache complexity. tRPC skips the schema layer entirely — TypeScript types are the contract — but only works inside a monorepo. ## REST vs GraphQL vs tRPC at a glance | Dimension | REST | GraphQL | tRPC | | --- | --- | --- | --- | | **Fetching** | Fixed shape per endpoint; over/under-fetch is common | Client declares exact fields; one round-trip for nested data | Typed procedure call; shape defined by server return type | | **Typing** | Manual or OpenAPI-generated; drift is possible | Schema + codegen (e.g. GraphQL Code Generator) | Inferred from router — zero codegen, instant type errors | | **Caching** | `Cache-Control: s-maxage` on GET; CDN caches by URL | POST bypasses CDN; persisted queries restore GET caching | TanStack Query handles client cache; no HTTP-level caching | | **Best fit** | Public APIs, CDN-cached reads, non-TS consumers | Diverse clients needing different field sets | Full-stack TypeScript monorepos only | ## Diagram ```mermaid flowchart LR Client -->|"GET /posts/:id\nHTTP caching"| REST["REST\nmulti-endpoint"] Client -->|"POST /graphql\nclient-shaped query"| GQL["GraphQL\nsingle endpoint"] Client -->|"trpc.post.byId\nshared TS types"| TRPC["tRPC\nmonorepo only"] REST --> DB GQL -->|DataLoader| DB TRPC --> DB ``` REST uses multiple endpoints with HTTP caching; GraphQL uses one endpoint with client-shaped queries; tRPC shares TypeScript types directly — no schema layer. ## tRPC router and typed client call Define typed procedures on the server; the exported `AppRouter` type is the sole contract. No schema file, no codegen step. ```ts // server/router.ts import { initTRPC } from "@trpc/server"; import { z } from "zod"; const t = initTRPC.create(); export const appRouter = t.router({ post: t.router({ byId: t.procedure .input(z.object({ id: z.string() })) .query(async ({ input }) => { return db.post.findUnique({ where: { id: input.id } }); }), }), }); export type AppRouter = typeof appRouter; // client/PostPage.tsx import { trpc } from "@/utils/trpc"; export function PostPage({ id }: { id: string }) { // Type of data is inferred from the router — no codegen. const { data } = trpc.post.byId.useQuery({ id }); return