What Is GraphQL? How It Differs From a REST API
GraphQL lets clients request exactly the data they need from a single typed endpoint. Here is what it is, how it works, and when it beats REST.
GraphQL is a query language for APIs, paired with a server-side runtime, that lets a client ask for exactly the data it needs in a single request instead of calling several fixed endpoints. Created at Facebook and now maintained by the independent GraphQL Foundation, it replaces REST's many resource URLs with one typed endpoint and a schema that describes every field a client is allowed to request.
What is GraphQL?
According to graphql.org, the project's own home, GraphQL is "an open-source query language for your API, and a server-side runtime for executing queries using a type system you define for your data." That type system — the schema — is the center of everything. It describes every object, field, and relationship your API can expose, written in GraphQL's own schema language, and it's the single source of truth both the server and every client code against.
In practice, a GraphQL API has one URL (for example GitHub's is https://api.github.com/graphql), and every request — whether it's reading data, writing data, or listening for updates — is a structured document of fields sent to that one endpoint rather than a different URL per resource.
Where GraphQL came from
GraphQL began inside Facebook, which has used it to power its mobile apps since 2012, long before the language was open-sourced and published publicly. It's now developed in the open and stewarded by the GraphQL Foundation, a neutral home under the Linux Foundation, which keeps the specification, the reference implementation, and the graphql.org documentation. That governance matters for an explainer like this one: GraphQL isn't a single vendor's product, it's a specification — which is why there are many independent server and client implementations, with Apollo being one of the most widely used platforms for building and operating GraphQL APIs in production.
The schema and type system
Every GraphQL API is built around a schema that defines types and the fields on them. A simple schema might look like this:
type User {
id: ID!
name: String!
email: String
posts: [Post!]!
}
type Query {
user(id: ID!): User
} |
The exclamation marks matter: String! means that field can never be null, while [Post!]! means the list itself and every item in it are guaranteed to exist. This is what graphql.org's documentation means when it describes GraphQL as providing "a complete and understandable description of the data" — the schema is both the API's contract and its documentation, and clients can query the schema itself (a feature called introspection) to discover every type and field without reading separate docs.
Because the type system is decoupled from any particular database, a GraphQL layer can sit in front of SQL tables, legacy REST services, or multiple backends at once — the schema describes "how clients use the data," not how it's stored underneath, which is part of why teams use GraphQL as an aggregation layer over older systems rather than rewriting them.
Queries, mutations, and subscriptions
GraphQL defines three operation types, all sent to the same endpoint:
- Queries read data. A client writes a query that mirrors the shape of the response it wants, and the server returns exactly that shape back under a
datakey. - Mutations change data — creating, updating, or deleting records — and, like queries, return whichever fields the client asks for from the result of that change.
- Subscriptions support real-time data, letting a client stay connected and receive updates as events happen on the server.
A query with variables looks like this, taken from the pattern documented in graphql.org's queries guide:
query HeroNameAndFriends($episode: Episode = JEDI) {
hero(episode: $episode) {
name
friends {
name
}
}
} |
The response mirrors that same nested shape exactly — no extra fields, no missing ones. Variables are sent separately from the query string, so values don't have to be string-interpolated into the request, and the same named query can be reused with different arguments.
GraphQL vs REST API: the key differences
REST organizes an API around resources, each with its own URL — /users/42, /users/42/posts, and so on — with the server deciding the exact shape of each response. GraphQL organizes an API around a single typed schema, with one endpoint and client-specified response shapes. Here's how the two styles compare on the dimensions that actually affect day-to-day development:
| Dimension | REST | GraphQL |
|---|---|---|
| Endpoints | Many, one per resource (/users, /posts) | One endpoint for all operations |
| Response shape | Fixed by the server for each endpoint | Specified by the client's query |
| Over/under-fetching | Common — extra fields, or multiple round trips | Avoided — client asks for exactly what it needs |
| Versioning | Typically versioned URLs (/v1, /v2) | Schema can add fields without breaking clients — graphql.org describes this as "versionless" evolution |
| Caching | Maps naturally onto HTTP caching (GET, CDNs, proxies) | Needs client- or gateway-level caching strategies |
| Discoverability | Documented separately (OpenAPI/Swagger, hand-written docs) | Self-documenting via introspection of the live schema |
| Real-time updates | Requires separate mechanisms (webhooks, polling) | Built into the spec as subscriptions |
Neither column is universally "better." REST's alignment with plain HTTP semantics is exactly why caches, CDNs, and load balancers already understand it, and why it remains the default for simple, public, resource-shaped APIs. GraphQL's single flexible endpoint earns its complexity when a client needs to assemble data from many related sources in one round trip, or when several very different clients (web, mobile, and partner integrations) all need different slices of the same underlying data.
A real-world example: GitHub's GraphQL API
GitHub's own documentation is one of the clearest public illustrations of why a large platform runs both API styles side by side. GitHub has offered a REST API for years, and it also runs a GraphQL API at the single endpoint https://api.github.com/graphql, which its docs describe as offering "more precise and flexible queries than the GitHub REST API." A client authenticates with a token in an Authorization: bearer header and sends a JSON body containing a GraphQL query string — for example, a query to fetch the authenticated user's login name — to that one URL, rather than calling a different REST endpoint for every resource it needs.
GitHub's GraphQL API has its own rate-limiting model, measured in points per hour rather than request counts: personal access tokens and most OAuth or GitHub App requests get 5,000 points per hour, rising to 10,000 or more for GitHub Apps and OAuth apps tied to an Enterprise Cloud organization, according to GitHub's rate-limit documentation. That point-based system exists specifically because a single GraphQL query can request a large, nested graph of data in one call — something a REST client would need many separate requests to assemble. Teams building automation against GitHub's data, including CI pipelines built on GitHub Actions, increasingly reach for the GraphQL endpoint specifically to pull related objects (a pull request, its reviews, and its linked issues, say) in one round trip instead of chaining several REST calls together.
What GraphQL is used for
In practice, teams reach for GraphQL in a handful of recurring situations:
- Multiple client types sharing one backend. A web app, an iOS app, and an Android app often need different subsets of the same data; GraphQL lets each client request its own shape from one schema instead of the backend team maintaining several bespoke REST endpoints.
- Aggregating several services behind one API. A GraphQL layer can sit in front of multiple databases, microservices, or even legacy REST APIs, presenting one coherent graph to the client while the server-side resolvers handle the underlying complexity.
- Complex, nested data needs. Screens that would otherwise require three or four chained REST calls — a user, their recent orders, and each order's line items, for instance — collapse into a single GraphQL query.
- Public developer platforms. GitHub, and companies like Shopify and PayPal, expose GraphQL APIs publicly so third-party developers can pull exactly the data their integration needs without GitHub or Shopify having to anticipate every possible REST endpoint shape in advance.
It's worth being clear about what it isn't automatically good for: a GraphQL endpoint doesn't make a service faster or more scalable by itself, and anything still has to be resolved by code on the server — the resolvers behind each field are ordinary application logic, often hitting the same databases a REST handler would.
The GraphQL tooling ecosystem
Because GraphQL is a specification rather than a single product, adopting it usually means choosing a server library and a client library. On the server side, teams use the reference JavaScript implementation or language-specific libraries; on the client side, Apollo Client and similar libraries handle sending queries, caching responses, and keeping local UI state in sync with the schema. Apollo's broader platform, GraphOS, adds schema registry, change validation, and gateway features for teams running GraphQL at larger scale — the kind of "federated" setup where one public schema is actually composed from several backend services' schemas. None of that tooling is required to use GraphQL; a small team can run a single GraphQL server with no gateway at all, the same way a small REST API doesn't need an API gateway on day one.
Should you use GraphQL? What to do next
If you're building a simple, resource-shaped public API — one where a handful of endpoints map cleanly onto the data your clients need — REST's simplicity, caching behavior, and universal tooling support still make it the easier default. If you're serving several very different clients off one growing data model, or your frontend teams keep hitting over-fetching and chained-request problems against a REST API, GraphQL's client-specified queries and single typed schema solve exactly that pain, and graphql.org's own Learn section is the right starting point for the spec itself.
The two aren't mutually exclusive, and plenty of real systems run both: a public, cacheable REST surface for simple resources alongside a GraphQL endpoint for the complex, multi-client parts of the same product — not unlike how a team might pair a vector database for similarity search alongside a conventional relational store rather than replacing one with the other. Before committing either way, read a real schema end to end — GitHub's public GraphQL docs or the schema behind any API you already call — and try rewriting one of your existing multi-call REST workflows as a single GraphQL query. That exercise alone usually makes the trade-off concrete.
Frequently asked questions
Is GraphQL a database?
No. GraphQL is a query language and runtime that sits in front of whatever stores your data — a SQL database, a NoSQL store, another API, or several of these at once. The schema describes the data's shape; it doesn't store the data itself.
Is GraphQL replacing REST?
No single answer fits every API. Large platforms like GitHub run REST and GraphQL side by side, and REST remains the default for simple, public, cache-friendly resources. GraphQL tends to get adopted alongside REST for complex, multi-client, or aggregated data needs rather than as a wholesale replacement.
Do I need Apollo to use GraphQL?
No. Apollo is one widely used platform (server, client, and the GraphOS tooling layer) for building and running GraphQL APIs, but GraphQL itself is an open specification with many independent implementations across languages.
What's the difference between a query and a mutation?
A query reads data and has no side effects. A mutation is explicitly for changing data — creating, updating, or deleting records — and the mutation keyword is required rather than optional the way query can be in shorthand syntax.
Does GraphQL support real-time updates?
Yes, through subscriptions, a third operation type alongside queries and mutations, which let a client stay connected to receive updates as events happen on the server.
Frequently asked questions
Is GraphQL a database?
No. GraphQL is a query language and runtime that sits in front of whatever stores your data — a SQL database, a NoSQL store, another API, or several of these at once. The schema describes the data's shape; it doesn't store the data itself.
Is GraphQL replacing REST?
No single answer fits every API. Large platforms like GitHub run REST and GraphQL side by side, and REST remains the default for simple, public, cache-friendly resources. GraphQL tends to get adopted alongside REST for complex, multi-client, or aggregated data needs rather than as a wholesale replacement.
Do I need Apollo to use GraphQL?
No. Apollo is one widely used platform (server, client, and the GraphOS tooling layer) for building and running GraphQL APIs, but GraphQL itself is an open specification with many independent implementations across languages.
What's the difference between a query and a mutation?
A query reads data and has no side effects. A mutation is explicitly for changing data — creating, updating, or deleting records — and the mutation keyword is required rather than optional the way query can be in shorthand syntax.
Does GraphQL support real-time updates?
Yes, through subscriptions, a third operation type alongside queries and mutations, which let a client stay connected to receive updates as events happen on the server.
Sources
- GraphQL.org — Introduction to GraphQLgraphql.org
- GraphQL.org — Queries and Mutations (Learn)graphql.org
- GraphQL.org — Learn sectiongraphql.org
- GitHub Docs — GraphQL API overviewdocs.github.com
- GitHub Docs — Rate limits for the GraphQL APIdocs.github.com
- Apollo GraphQL — Documentationapollographql.com
Felix Moreau writes Pandromeda's software coverage and how-to guides. He covers Windows, macOS and Linux updates, the apps people rely on, emulators and developer tools, and turns official documentation into clear, numbered steps that work on the current version.