Research-based overview. This article synthesizes the official GraphQL specification, Apollo’s and Relay’s published documentation, the GraphQL Foundation’s state-of-the-ecosystem reports, and public adoption patterns from Hasura, PostGraphile, and GraphQL Yoga. How we research.

One-sentence definition
GraphQL is a query language for APIs and a runtime for fulfilling those queries, developed at Facebook in 2012 and open-sourced in 2015. It lets clients specify the exact shape of the data they want from a server in a single request, instead of accepting whichever fixed-shape response a REST endpoint happens to return.

GraphQL is a piece of API technology everyone has heard of, fewer have built with, and even fewer have built with at a scale where the trade-offs become real. The public conversation is dominated by people running it at large companies with cross-platform engineering teams — where the rationale is genuinely compelling. It rarely addresses what GraphQL looks like in a single-developer Next.js codebase, which is where most solo SaaS work happens. The short answer for that audience is “probably not GraphQL,” but the long answer is more interesting.

The problem GraphQL solves

Facebook’s engineers in the early 2010s had a specific pain. They were rebuilding the Facebook mobile app from a HTML5 wrapper to native iOS and Android. Native apps needed different shapes of data than the web app — a mobile newsfeed cell shows different fields than a web feed item, profile screens differ across iOS, Android, and web.

With REST, every screen needed a specific endpoint, or the client had to call multiple endpoints and stitch results together. Both options scaled badly: backend teams built dozens of near-duplicate endpoints, and mobile clients made too many requests over flaky networks.

GraphQL was the answer. A single endpoint accepts a query describing exactly which fields the client wants. The server returns a response in that shape. Backend teams stop building screen-specific endpoints; clients stop over-fetching.

A worked example

Consider a user profile screen that needs to show a user’s name and avatar, their last five posts (with title, date, comment count), and the unread notification count.

With a typical REST API, this requires three or four requests:

With GraphQL, this is a single request:

query ProfileScreen($userId: ID!) { user(id: $userId) { name avatarUrl posts(limit: 5) { title publishedAt commentCount } unreadNotificationCount } }

The server returns precisely the fields requested, nothing more. No over-fetching, no waterfall of network requests, one round-trip instead of three. On a slow mobile network, the difference between one round-trip and three is the difference between a screen that feels instant and a screen that feels broken.

The three operation types

GraphQL splits operations into three categories:

Each operation type has different infrastructure requirements. Queries and mutations work over plain HTTP. Subscriptions need a persistent connection layer that is more expensive to operate. Many SaaS apps use GraphQL for queries and mutations and reach for a different tool (Pusher, Ably, Supabase Realtime) for the subscription layer.

Schema-first development

You define a type schema in SDL (Schema Definition Language) that describes every type, field, and operation your API exposes. The schema is the contract between client and server.

A minimal schema for the profile example:

type User { id: ID! name: String! avatarUrl: String posts(limit: Int = 10): [Post!]! unreadNotificationCount: Int! } type Post { id: ID! title: String! publishedAt: String! commentCount: Int! } type Query { user(id: ID!): User }

The tooling ecosystem generates TypeScript types, mock servers, query explorers (GraphiQL, Apollo Sandbox), and docs from the schema. The schema is the single source of truth — when it is right, every downstream artifact stays in sync automatically.

The major implementations

For a solo founder evaluating GraphQL today: Hasura or PostGraphile is lowest-friction if you already have Postgres; Apollo or Yoga is the right pick if you want to write the schema by hand.

The N+1 problem

GraphQL’s biggest operational gotcha is the N+1 problem. Consider a query that asks for a list of posts and the author of each post:

query { posts(limit: 20) { title author { name } } }

A naive resolver does one query for the posts (the “1”), then one query per post for the author (the “N”). For 20 posts, 21 database queries. At scale, this kills the database.

The standard solution is DataLoader, a batching-and-caching utility from Facebook. It collects all author-id lookups within a single execution, batches them into one query (WHERE id IN (...)), and caches within the request lifecycle. With DataLoader the query becomes two calls: one for posts, one batched call for all authors.

The trap: DataLoader is not automatic. You configure it for every relation that might trigger N+1, which is most of them. New developers on a GraphQL codebase routinely ship N+1 bugs because they did not know DataLoader existed for that field.

Caching is harder than REST

REST caches trivially: every endpoint is a URL, CDNs handle the rest. GraphQL throws this away because every request is a POST to the same /graphql endpoint. CDN-level HTTP caching does not work out of the box.

The workarounds:

None of this is fatal, but it is meaningfully more complex than REST + CDN. For founders who want HTTP caching to mostly just work, GraphQL is a step backward.

Authorization is harder too

REST authorization is endpoint-level: check permissions, return 403, done. GraphQL has to authorize at the field level because a single query can touch many resources. { user(id: 1) { posts { author { email } } } } requires checks at each field. Libraries like GraphQL Shield and Apollo’s permission directives exist, but it takes more careful design than REST’s endpoint-level checks. Permission bugs in GraphQL apps often manifest as “a field that should have been gated was not.”

File uploads

GraphQL is JSON-only and does not handle binary data natively. Two workable patterns:

When GraphQL fits

When REST wins

GraphQL vs REST vs tRPC

The three options solo SaaS founders actually pick between:

OptionStrengthsTrade-offs
RESTHTTP-native, widely understood, easy CDN caching, no extra runtimeFixed response shapes, over-fetching on rich screens, multiple round-trips for nested data
GraphQLFlexible queries, schema-first, single round-trip for nested data, strong toolingN+1 risk, harder caching, harder authorization, file uploads awkward, more concepts to learn
tRPCEnd-to-end TypeScript types, no schema duplication, fastest DX in a Next.js monorepoTypeScript-only, no third-party clients, no GET caching for queries by default, smaller ecosystem

For most solo SaaS founders building a Next.js app where client and server share a TypeScript codebase, tRPC beats GraphQL. Every server procedure is automatically typed on the client, refactors propagate end-to-end, and there is no schema, no codegen, no second language. tRPC ate the role GraphQL was reaching for in the TypeScript ecosystem — not because GraphQL is worse, but because the stack going all-TypeScript solved the client-server type-contract problem a different way.

GraphQL still wins for the multi-platform case, the public-API case, and federation — but those are not the cases most solo founders are in.

The honest take for solo SaaS

Do not adopt GraphQL by default. The complexity is real, the footguns are real, and the wins do not materialize until you have multiple clients with diverging data needs or a federated services architecture. For a single Next.js app with a single Postgres backend, REST or tRPC moves faster and breaks less often.

Reach for GraphQL when you have a mobile + web + partner-API surface, when your relational data model needs traversal flexibility on the client, or when you are joining a codebase that already runs GraphQL.

If you do go GraphQL: learn DataLoader early, plan authorization before you ship, and decide consciously whether you need subscriptions or whether queries and mutations are enough. Related infrastructure trade-offs are covered in what is a CDN, SaaS database schema patterns, what is an ORM, Supabase RLS for multi-tenant SaaS, what is a JWT, and what is a webhook. The best SaaS tools for developers roundup places each in a modern stack.

One sentence: GraphQL is a powerful tool for a specific class of problems most solo SaaS founders do not have. REST for simple cases, tRPC for TypeScript monorepos, GraphQL when the multi-client or relational-graph nature of your problem makes the trade-off worth paying.

Get one SaaS build breakdown every week

The stack, prompts, pricing, and mistakes to avoid — for solo founders building with AI.