GraphQL
A query language for APIs where the client specifies exactly what data it needs. No over-fetching, no under-fetching. One endpoint to rule them all.
What is GraphQL?
In short
GraphQL is a query language and runtime for APIs where the client sends a single request describing the exact shape of the data it wants, and the server returns precisely that, nothing more and nothing less. It exposes one endpoint instead of many, so clients ask for the fields they need across multiple related objects in one round trip.
What GraphQL actually is
GraphQL is a specification, originally built at Facebook in 2012 and open-sourced in 2015, for how clients ask servers for data. Instead of a server defining a fixed set of REST endpoints like /users/42 and /users/42/posts, a GraphQL server publishes a single endpoint (usually /graphql) backed by a typed schema. The client writes a query that names the exact fields it wants, and the server resolves that query against its data sources.
The schema is the contract. It declares types (User, Post, Comment), the fields on each type, and how they connect. Because everything is strongly typed, tools can validate a query before it ever runs, generate documentation automatically, and power editor autocomplete. There are three root operation types: query for reads, mutation for writes, and subscription for a stream of real-time updates over a persistent connection.
The headline benefit is no over-fetching and no under-fetching. A mobile screen that needs a user's name and the titles of their last three posts asks for exactly those fields. A REST equivalent might force two or three round trips, or return a fat JSON blob with 40 fields the client throws away.
How it works under the hood
When a query arrives, the server parses it into an abstract syntax tree, validates it against the schema, and then executes it. Execution walks the query field by field, calling a resolver function for each field. A resolver for User.posts knows how to fetch posts for a given user; a resolver for Post.author knows how to fetch the author. The engine stitches all these results into a single JSON response shaped exactly like the query.
This per-field resolution is powerful but introduces the N+1 problem. If you ask for 50 users and each user's company, a naive server runs 1 query for the users plus 50 queries for the companies. The standard fix is DataLoader, a batching and caching layer that collects all the company IDs requested during one tick of the event loop and fetches them in a single batched query.
Because there is one endpoint and queries vary in shape, GraphQL also shifts how you handle caching, errors, and security. HTTP caching by URL no longer works since every request hits /graphql, so caching moves to the client (Apollo Client, Relay, urql normalize results by object ID) or to persisted queries. Errors come back in an errors array alongside partial data rather than as HTTP status codes.
When to use it and the trade-offs
GraphQL shines when many different clients with different data needs hit the same backend: a web app, an iOS app, and an Android app that each want slightly different fields. It also fits well when your data is graph-like with many relationships, and when frontend teams want to move fast without waiting for backend teams to ship a new endpoint for every screen.
The costs are real. The flexible query surface makes it easier for a client to craft an expensive query, so you need query depth limits, complexity scoring, and timeouts to avoid denial-of-service through a single deeply nested request. Caching is harder than REST's URL-based model. File uploads, rate limiting, and HTTP status semantics all need extra work because everything is a POST to one endpoint.
A common pattern is to not replace REST everywhere. Teams often put GraphQL in front of existing REST services or microservices as a gateway (a BFF, backend for frontend), letting GraphQL aggregate and reshape data while the underlying services stay REST. For simple internal services with one consumer, plain REST or gRPC is usually less overhead.
A concrete example
Suppose a profile page needs a user's name, their avatar, and the titles of their three most recent posts. In GraphQL the client sends one query: query { user(id: 42) { name avatarUrl posts(last: 3) { title } } }. The response mirrors that exactly, returning a name string, an avatarUrl string, and an array of three objects each with a title.
With REST the same screen might call GET /users/42 to get the profile, then GET /users/42/posts?limit=3 to get the posts, costing two round trips and likely returning more fields than the screen uses. On a slow mobile network those extra round trips and bytes show up directly as a slower page.
This is why GitHub rebuilt its public API as GraphQL: clients building dashboards over issues, pull requests, and repositories were making dozens of REST calls and stitching the results themselves. One GraphQL query lets a client fetch a repository, its open issues, and each issue's labels and assignees in a single request.
Where it is used in production
GitHub
Its v4 public API is GraphQL, letting clients fetch repositories, issues, pull requests, and their nested fields in one query instead of dozens of REST calls.
Meta (Facebook)
Created GraphQL to power its News Feed and mobile apps, where each screen needs a different slice of a deeply connected social graph.
Shopify
Exposes its Admin and Storefront APIs over GraphQL so merchants and storefronts request exactly the product, order, and inventory fields they render.
Netflix
Runs a federated GraphQL gateway (Domain Graph Service) that stitches many backend microservices into one schema for its studio and UI teams.
Frequently asked questions
- Is GraphQL a replacement for REST?
- Not necessarily. GraphQL solves over-fetching and multi-endpoint round trips, which matters for apps with many clients and graph-like data. For a simple service with one consumer, REST or gRPC is often simpler. Many teams run GraphQL as a gateway in front of existing REST services rather than ripping REST out.
- What is the N+1 problem in GraphQL?
- When a query asks for a list and a related field on each item, a naive resolver runs one query for the list plus one query per item, for example 1 + 50 queries to load 50 users and each user's company. The standard fix is DataLoader, which batches all those lookups within one event-loop tick into a single query.
- Does GraphQL use GET or POST?
- Queries are almost always sent as a POST to a single /graphql endpoint with the query in the request body, though the spec allows GET for read-only queries. Because the URL never changes, you cannot rely on HTTP URL caching; caching moves to the client or to persisted queries instead.
- How do you secure a GraphQL API?
- The flexible query surface lets clients craft expensive nested queries, so you add query depth limits, complexity scoring, timeouts, and pagination caps to prevent denial of service. Authentication and authorization happen in resolvers, and persisted (allow-listed) queries can restrict clients to known-safe queries in production.
- What are queries, mutations, and subscriptions?
- Query is for reading data, mutation is for writing or changing data, and subscription opens a persistent connection (often over WebSockets) so the server can push real-time updates, such as a new chat message, to the client as they happen.
Learn GraphQL hands-on
This page explains the idea. The full lesson lets you step through the ring as servers join and leave, read the implementation, and check yourself with a quiz. It is one of 760+ lessons in the System Design Masterclass, from your first API call to distributed consensus. Eleven Foundation lessons are free, no signup. Lifetime access is ₹499 in India or $7.99 worldwide, one payment, no subscription.
Related lessons
Lessons that touch on GraphQL as part of a larger topic.
See also
Related glossary terms you might want to look up next.
REST API
An architectural style for building APIs using standard HTTP methods (GET, POST, PUT, DELETE). Resources are identified by URLs.
gRPC
A high-performance RPC framework by Google using Protocol Buffers and HTTP/2. Much faster than REST for service-to-service communication.
HTTP
The protocol powering the web. A request-response model where clients ask for resources and servers respond. Stateless by design.
WebSocket
A protocol for full-duplex communication over a single TCP connection. Unlike HTTP, the server can push data to the client without being asked.
SSE
Server-Sent Events: a one-way channel where the server pushes updates to the client over HTTP. Simpler than WebSockets when you only need server-to-client streaming.
Rate Limiting
Controlling how many requests a client can make in a given time window. Protects your API from abuse and ensures fair usage.