Skip to content
All articles
Articleapipostgrestgraphqltrpc

PostgREST vs GraphQL vs tRPC in 2026

Three flavors of 'API on top of your database' and how to pick. Honest 2026 comparison of PostgREST, GraphQL, and tRPC, with the AI-paired angle baked in.

12 min read

The eternal "which API layer" question. PostgREST gives you a REST API by introspecting your database. GraphQL gives you a schema-driven query language with deep client tooling. tRPC gives you typed RPC over HTTP with zero schema language. By 2026 all three have settled into roles where they win cleanly.

What each one actually is

  • PostgREST: a small server that exposes your Postgres schema as a REST API. URL paths map to tables. RLS does the authz. Zero application code.
  • GraphQL: a query language + a typed schema you maintain. Clients ask for exactly the fields they need; one HTTP endpoint serves all queries.
  • tRPC: typed RPC procedures in TypeScript. The client imports the server's types directly; calls are end-to-end type-safe. No schema language, no codegen.

PostgREST

The default when you're on Supabase. It's already there; every Supabase project exposes its schema as REST out of the box.

bash
GET /rest/v1/posts?select=id,title&status=eq.published&order=created_at.desc&limit=10
# Returns published posts. RLS evaluated server-side.

Wins: zero server code; OpenAPI doc generated automatically; RLS-native authz; perfect for AI agents that can read the introspection.

Trade-offs: the API shape mirrors your schema, so a poor schema produces a poor API; complex business logic still needs a real server somewhere.

GraphQL

The right choice when you have many client teams (web, mobile, third parties) with different field needs against the same data, or a large existing schema you want a polished query interface for.

Wins: client-side query flexibility; mature tooling (Apollo, Relay, urql); excellent federation story for microservices.

Trade-offs: a schema you maintain alongside your database schema. Resolvers are server code. N+1 query problems are a constant maintenance concern (dataloaders solve, but only if wired up).

tRPC

TypeScript end-to-end. Define procedures on the server; import them as functions on the client. Types flow without any schema language.

server.tsts
export const appRouter = router({
  posts: router({
    list: publicProcedure
      .input(z.object({ status: z.enum(["draft","published"]).optional() }))
      .query(async ({ input }) => {
        return db.select().from(posts)
          .where(input.status ? eq(posts.status, input.status) : undefined);
      }),
  }),
});
client.tsts
const data = await trpc.posts.list.query({ status: "published" });
// data is fully typed: Post[]

Wins: end-to-end type safety without codegen; delightful DX for TypeScript-first teams; perfect for AI-paired coding because every call is a typed function.

Trade-offs: TypeScript-only client/server. Not the right call when non-TS clients (mobile native, third-party integrations) need to consume the same API.

How to decide

  • You're on Supabase and shipping a TypeScript-only frontend: PostgREST is already there. Use it for the 80% and add tRPC for the 20% of business logic that doesn't fit REST.
  • You have multiple client surfaces (web + iOS + Android + partners): GraphQL pays for itself.
  • You're a small team shipping a TS-only product fast: tRPC. Minimum overhead, maximum type safety.
  • You're a public API for third parties: REST (handwritten or PostgREST-derived). Third-party developers expect REST.

For AI-paired projects specifically, the type-safe options (PostgREST + introspection, tRPC) win. The agent reads types; types describe the API; the agent writes correct callers. GraphQL works but the second schema layer is more for the agent to synchronise.

Suparbase is an admin workspace for Supabase. Encrypted credentials, server-side proxy, RLS debugger, SQL playground, AI assistant with diff-confirmed writes. Free tier for solo projects.

Related articles