GraphQL
A query language and runtime for APIs: the server publishes a typed schema, and each client asks one endpoint for exactly the fields it needs.
- What it is
- Web APIs
- Type
- Open source
- Made by
- GraphQL Foundation (Linux Foundation), created at Facebook
- License
- Specification: Open Web Foundation Agreement 1.0 since September 2017; GraphQL.js reference implementation: MIT since September 2017 (BSD plus a patent grant before)
- Facts checked
- 9 October 2026
What it is
A GraphQL service publishes a schema written in GraphQL’s type language: object types with typed fields, such as an Order with a status and a customer, plus root types listing the entry points for queries (reads), mutations (writes) and subscriptions (streams of events). Clients send a document to one endpoint, conventionally POST /graphql with a JSON body holding the query and its variables. The server parses the document and validates it against the schema before running anything, then executes it. Every field is backed by a resolver, a function that gets its parent object and the field’s arguments and returns a value from a database, another service or memory. Query fields may resolve in parallel; the top-level fields of a mutation run one after another. The response is JSON with the data under data, shaped exactly like the query, and any problems under errors, so one response can carry partial data and errors together. The schema can itself be queried (introspection), which powers editors such as GraphiQL, code generators and typed clients.
The specification defines the language, type system, validation and execution, and deliberately leaves out transport and storage. HTTP with JSON is the usual pairing, described by a separate GraphQL over HTTP specification that is still a draft; subscriptions usually run over WebSockets or server-sent events. GraphQL.js is the reference implementation (v17 shipped in June 2026), and there are servers for most languages, such as Apollo Server, GraphQL Yoga, graphql-java and Strawberry, plus engines that generate a schema from a database. The GraphQL Foundation, part of the Linux Foundation, publishes the spec in dated editions; the September 2025 edition, the first since October 2021, added OneOf input objects and schema coordinates. Using GraphQL costs nothing; managed services such as AWS AppSync charge per operation.
Why teams pick it
- Each client asks for exactly the fields it needs, across related objects, in one request: fewer round trips and smaller payloads on mobile networks
- A typed schema: queries are validated before they run, and introspection drives GraphiQL, code generation and typed clients
- Evolves without version numbers: new fields don’t affect existing queries, and old ones are marked
@deprecatedwhile they keep working - One endpoint over many backends: resolvers can call databases, REST APIs and gRPC services, so a GraphQL layer can unify existing systems
- Subscriptions use the same schema and query language as reads, for real-time updates
Watch out for
- HTTP caching is harder: requests are usually
POSTs to one URL, which browsers and CDNs don’t cache. You needGETwith persisted queries, or client-side caches keyed by globally unique object IDs - The N+1 problem: naive resolvers make one backend call per item in a list, so 50 orders can mean 50 customer lookups. Batching with a tool like DataLoader is effectively required
- Clients write the queries, so a deep or wide one can overload the server. Public APIs need depth limits, cost analysis or rate limits by cost; GitHub charges points per query, 5,000 an hour per user, and requires a page size on every list
- Errors don’t map to HTTP status codes: a response with partial data comes back as
200with anerrorslist, so monitoring by status code misses failures - File uploads aren’t in the spec: servers adopt a community multipart convention, and graphql.org recommends uploading through signed URLs instead
Alternatives
What all web apis have in common →How it fits with other technologies
A GraphQL Yoga server with resolvers and DataLoader batching · ts
// npm install graphql graphql-yoga dataloader pg
import { createServer } from "node:http";
import { createSchema, createYoga } from "graphql-yoga";
import DataLoader from "dataloader";
import pg from "pg";
const db = new pg.Pool(); // connection settings from PGHOST, PGUSER, PGDATABASE...
const typeDefs = /* GraphQL */ `
type Query {
order(id: ID!): Order
recentOrders(first: Int = 20): [Order!]!
}
type Order {
id: ID!
status: String!
customer: Customer!
}
type Customer {
id: ID!
name: String!
}
`;
const resolvers = {
Query: {
order: async (_: unknown, { id }: { id: string }) =>
(await db.query("SELECT id, status, customer_id FROM orders WHERE id = $1", [id])).rows[0] ?? null,
recentOrders: async (_: unknown, { first }: { first: number }) =>
(await db.query("SELECT id, status, customer_id FROM orders ORDER BY created_at DESC LIMIT $1", [Math.min(first, 100)])).rows,
},
Order: {
// Runs once per order; the loader turns 20 calls into one query (no N+1)
customer: (order: { customer_id: string }, _: unknown, ctx: { customers: DataLoader<string, unknown> }) =>
ctx.customers.load(order.customer_id),
},
};
const yoga = createYoga({
schema: createSchema({ typeDefs, resolvers }),
// A fresh loader per request, so batches and its cache never mix users
context: () => ({
customers: new DataLoader<string, unknown>(async (ids) => {
const { rows } = await db.query("SELECT id, name FROM customers WHERE id = ANY($1)", [ids]);
return ids.map((id) => rows.find((row) => row.id === id) ?? null);
}),
}),
});
createServer(yoga).listen(4000); // POST http://localhost:4000/graphql
// Client: { recentOrders(first: 20) { id status customer { name } } }What a server does with a request#
The spec defines each step as an algorithm, so every conforming server, in any language, runs them in this order. Anything that fails before execution is a request error: the response has errors and no data at all.
| What happens | If it fails | |
|---|---|---|
| 1. Parse | The document text becomes a syntax tree of operations and fragments | Syntax error: request error, nothing runs |
| 2. Validate | The operation is checked against the schema: every field exists on its type, objects get a selection of subfields and leaf fields don’t, fragments don’t form cycles. A server may skip this for a document it has validated before and that hasn’t changed, such as a persisted query | Validation errors: request error, nothing runs |
| 3. Pick the operation and coerce variables | If the document holds several operations, the client names one. Variable values are converted to their declared types | Missing operation name or a wrong variable type: request error |
| 4. Execute | Resolvers run from the root fields down. Query fields can run in any order, normally in parallel, because they must be free of side effects; the top-level fields of a mutation run one after another. Each value is coerced to its schema type, so an enum stored as a number comes back as its name | Execution error: that field becomes null and the error goes into errors with its path. A null in a non-null field spreads up to the nearest nullable parent |
| 5. Respond | A map with data shaped like the query, errors if any were raised, and optional extensions, usually serialized as JSON. A subscription returns a stream of these results, one per event | Nothing new: errors raised earlier are already in the response |
Introspection: the schema answers questions about itself#
Every GraphQL service can be queried about its own schema, in GraphQL. The meta-field __typename works in any selection set (except at the root of a subscription) and returns the name of the concrete object type, which is how a client tells the members of a union or interface apart. The query root also has two hidden fields: __schema, which lists every type, the root operation types and the directives, and __type(name: "Book"), which describes one type. Introspection types and fields start with two underscores (__Type, __Field, __EnumValue and so on), a prefix your own names may not use.
Everything in a schema can carry a description, which may be written in Markdown, and fields, arguments, input fields and enum values report isDeprecated and a deprecationReason. That is what lets GraphiQL autocomplete queries and show documentation, and lets code generators produce typed clients. graphql.org notes that APIs used only by your own apps rarely need introspection in production, because their queries are fixed at build time, and that disabling it is a common way to shrink the attack surface.
REST, GraphQL and gRPC#
All three run over HTTP, but they put the contract, and the choice of what comes back, in different places.
| REST | GraphQL | gRPC | |
|---|---|---|---|
| Contract | Optional, often an OpenAPI document | A schema, required; clients can query it | A .proto file, required |
| Endpoints | One URL per resource | One, usually /graphql | One path per method, /package.Service/Method |
| Who shapes the response | The server, per endpoint | The client, per query | The server, per message type |
| Encoding | Usually JSON | Usually JSON; the spec doesn’t require one | Binary Protobuf by default |
| HTTP caching | Built in: GET with Cache-Control and ETag | Only with GET or persisted queries; otherwise client-side caches | Not used |
| Errors | HTTP status codes | An errors list in the body, often with status 200 | Status code in HTTP/2 trailers |
| Real-time | Not defined by the style | Subscriptions; the transport is left to the implementation | Server, client and bidirectional streaming |
| From a browser | Directly | Directly | Only through gRPC-Web and a proxy |
Ways to run a GraphQL API#
You can write resolvers yourself, generate the schema from a database, or rent a managed service. AWS list prices checked October 6, 2026.
GraphQL.js
reference, MITThe JavaScript reference implementation maintained by the GraphQL Foundation; v17 shipped in June 2026. Many Node servers build on it.
Apollo Server and GraphQL Yoga
Node servers, MITFull HTTP servers around GraphQL.js. Other languages have their own, such as graphql-java. In Python, Strawberry, Ariadne and Graphene all run on GraphQL-core, a close Python port of GraphQL.js.
Hasura, PostGraphile, pg_graphql
generatedBuild a GraphQL schema from an existing database. pg_graphql runs inside PostgreSQL as an extension and is called through one SQL function, graphql.resolve.
AWS AppSync
managedResolvers connect fields to DynamoDB, Lambda, OpenSearch, RDS, EventBridge or HTTP endpoints. $4.00 per million queries and mutations, $2.00 per million real-time updates, $0.08 per million connection-minutes.
Azure API Management
managedPasses GraphQL through to an existing server, or builds a synthetic GraphQL API from a schema with resolvers that call HTTP backends.
Firebase Data Connect
managedGoogle’s managed GraphQL API over Cloud SQL for PostgreSQL, with generated, type-safe SDKs for web and mobile apps.
Editions of the specification#
The spec is published as dated editions at spec.graphql.org, with a working draft in between. Seven editions have appeared since 2015.
| Status | Notable changes | |
|---|---|---|
| July 2015 | Working draft, technical preview | First public release, published as a work in progress |
| October 2015 | Working draft | First of the tagged releases with a changelog, after three months of feedback |
| April 2016 | Working draft | Mostly clarifications; directive introspection reports locations instead of three booleans |
| October 2016 | Working draft, preview label removed | The null literal, full algorithms for execution, unique directives per location |
| June 2018 | First edition no longer a “Draft RFC” | The type system definition language (SDL), subscriptions, error paths, block strings, extensions on errors; relicensed under OWFa 1.0 |
| October 2021 | First edition ratified by the GraphQL Foundation | Interfaces implementing interfaces, repeatable directives, @specifiedBy URLs for custom scalars |
| September 2025 | Current edition | OneOf input objects, schema coordinates, descriptions on queries and other executable documents, wider deprecation, full Unicode |
- Dates and changes from each edition’s release notes on GitHub and the September 2025 announcement, checked on 2026-10-09.
See it in a real stack
No architecture uses GraphQL yet. Drop it into the playground and wire it up yourself.Open playground →Where it came from2012–2026
In 2012 Facebook began rebuilding its iOS and Android apps, which until then were thin wrappers around the mobile website and often slow and crash-prone. Native apps needed News Feed as data, not HTML. The team looked at RESTful resources and FQL, Facebook’s SQL-like API, and was frustrated by the gap between the data the apps wanted and the server queries they had to make. A few engineers started the project that became GraphQL, and a native iOS News Feed built on it shipped that year.
Facebook released a working draft of the spec and GraphQL.js as a “technical preview” in July 2015, after the excitement around Relay, its GraphQL-based app framework. By then GraphQL served hundreds of billions of API calls a day inside Facebook. In September 2016 it dropped the preview label, the day GitHub announced the first major public GraphQL API.
In September 2017 Facebook relicensed the spec under the Open Web Foundation Agreement and GraphQL.js under MIT, dropping the separate patent grant that had come with its BSD licence. In November 2018 the Linux Foundation announced a GraphQL Foundation with members including Airbnb, Apollo, GitHub, Shopify and Twitter, and from March 2019 the spec has been developed under the Joint Development Foundation.
Why it’s built this way
- A protocol, not a database
- Facebook already had feed ranking, storage and business logic. So each field is backed by a function that can call any existing code, and GraphQL provides no storage of its own.
- Queries shaped like the screen
- A query follows relationships between objects in one request, where a RESTful service might need several round trips, which are expensive on mobile networks. The response mirrors the query.
- A strongly typed, introspective schema
- Typed fields let the server reject bad queries with clear errors before running them and suited the typed Objective-C and Java apps. Because the schema can be queried, tools like GraphiQL and Relay can build on it.
- No version numbers
- The client’s query decides the shape of the data, so new fields don’t affect existing clients and old ones can be deprecated but keep working. In 2015 Facebook said it still supported three years of app releases on one version of its API.
Timeline
- 2012
Built at Facebook for the native News Feed on iOS
- 2015
Draft spec and GraphQL.js released as a technical preview in July
- 2016
Preview label dropped; GitHub launches a public GraphQL API
- 2017
Spec relicensed under OWFa 1.0, GraphQL.js under MIT
- 2019
GraphQL Foundation launches under the Linux Foundation
- 2025
September edition of the spec, the first since 2021
- 2026
GraphQL.js v17 released in June
- GraphQL blog: GraphQL, a data query language (Lee Byron, September 2015)
- GraphQL blog: Leaving technical preview (September 2016)
- GitHub: graphql/graphql-js commit “GraphQL technical preview” (July 2015)
- GitHub: graphql/graphql-spec commit “Add OWFa v1.0 license agreement” (September 2017)
- GitHub: graphql/graphql-js commit “Relicense as MIT” (September 2017)
- Linux Foundation: Intent to form the GraphQL Foundation (November 2018)
- GraphQL blog: Collaboration with the Joint Development Foundation (March 2019)
- GraphQL blog: Announcing the September 2025 edition of the GraphQL specification
- GraphQL blog: Introducing GraphQL.js v17 (June 2026)
Sources40 · facts checked 9 October 2026
- GraphQL specification, September 2025 edition (execution algorithms, request and execution errors, introspection, serial mutations, transport-agnostic)
- GraphQL specification versions (seven editions since July 2015)
- GraphQL docs: Validation (parse then validate before execution)
- GraphQL docs: Execution (resolvers, concurrency, scalar coercion)
- GraphQL docs: Introspection (__typename, __schema, disabling in production)
- GitHub release: GraphQL spec July 2015 edition
- GitHub release: GraphQL spec October 2015 edition
- GitHub release: GraphQL spec April 2016 edition
- GitHub release: GraphQL spec October 2016 edition
- GitHub release: GraphQL spec June 2018 edition (no longer a Draft RFC, SDL, subscriptions)
- GitHub release: GraphQL spec October 2021 edition (first ratified by the GraphQL Foundation)
- GraphQL spec: October 2021 changelog
- GraphQL blog: Announcing the September 2025 edition of the GraphQL specification
- GitHub: graphql/graphql-spec LICENSE.md (OWFa 1.0 for the spec, MIT for code)
- GitHub: graphql/graphql-js (MIT)
- GraphQL Foundation (created 2019, hosted by the Linux Foundation)
- GraphQL docs: Serving over HTTP (single endpoint, POST and GET, GraphQL over HTTP draft, status codes)
- GraphQL docs: Caching (globally unique IDs)
- GraphQL docs: Performance (GET and persisted queries, N+1 and DataLoader)
- GraphQL docs: Security (depth limiting, complexity analysis, trusted documents, subscriptions over WebSockets or SSE)
- GraphQL docs: File uploads (multipart convention, signed URLs recommended)
- GraphQL docs: Schema design (evolving without versions)
- GraphQL blog: Wrapping a REST API in GraphQL (Steven Luscher, May 2016)
- GitHub: graphql/dataloader (batching and per-request caching)
- GitHub: graphql-multipart-request-spec
- GitHub docs: Rate limits and query limits for the GraphQL API (points, first or last required)
- GitHub: GraphQL Yoga README (createYoga, createSchema)
- GitHub: Apollo Server
- GitHub: graphql-java
- GitHub: Strawberry GraphQL
- GitHub: graphql-python/graphql-core README (Python port of GraphQL.js; used by Graphene, Ariadne and Strawberry)
- GitHub: Hasura GraphQL Engine
- GitHub: PostGraphile (graphile/crystal)
- pg_graphql docs (PostgreSQL extension, graphql.resolve)
- AWS AppSync docs: Data sources
- AWS AppSync pricing
- Microsoft Learn: Overview of GraphQL APIs in Azure API Management
- Firebase docs: Firebase Data Connect
- gRPC over HTTP/2 protocol specification (paths, trailers)
- gRPC docs: gRPC-Web basics (browser calls through a proxy)