API Query Language

GraphQL

GraphQL lets clients ask for exactly the data they need, in one request. A typed schema describes the API, and resolvers fetch the data behind it.

intermediate14 min readUpdated Sep 15, 2026
query.graphql
graphql
// query.graphql
query UserWithPosts($id: ID!) {
  user(id: $id) {
    name
    posts(first: 3) {
      title
    }
  }
}
Created by
Facebook, 2012
Released
2015, open source
Schema
A typed contract
Operations
Query, mutation, subscription
Transport
Usually HTTP, one endpoint
Server
Resolvers behind the schema

Why it matters

Why teams adopt GraphQL

Ask for what you need

Clients select the exact fields they use, so responses are neither over-fetched nor under-fetched.

One request, many resources

A single query can traverse relationships that would otherwise require several REST round trips.

A typed contract

The schema is self-documenting and enables autocompletion, validation and code generation.

The big picture

The three ideas behind GraphQL

A typed schema describes the data, a query selects exactly what is needed, and resolvers supply each field.

The schema

Contract

Types, fields and operations that describe exactly what the API can return.

The query

Select

A client document that selects fields and passes arguments and variables.

The resolvers

Resolve

Functions that fetch the data for each field, often from databases or services.

GraphQL at a glance

The core of GraphQL

Types and schema

Object types, scalars, enums, interfaces and unions.

Queries

Read data by selecting fields from the root query type.

Mutations

Write data, with an explicit input and a defined return shape.

Subscriptions

Stream real-time updates over a persistent connection.

Variables and fragments

Reuse field selections and pass typed arguments.

Clients

Apollo, urql and Relay handle caching and requests.

A short history

From an internal Facebook API to an industry standard

  1. 2012

    Built at Facebook

    Facebook creates GraphQL to power its mobile apps with efficient data fetching.

    12
  2. 2015

    Open sourced

    The specification and reference implementation are released publicly.

    15
  3. 2018

    Foundation formed

    The GraphQL Foundation is created to steward the specification.

    18
  4. 2020

    Mainstream adoption

    Apollo, urql and Relay mature, and GraphQL becomes common in product APIs.

    20
  5. Today

    A standard tool

    Widely used for public APIs, internal services and federated graphs.

    Today

The complete guide

GraphQL: Everything you need to know

What is GraphQL?

GraphQL is a query language and runtime for APIs. Instead of exposing many fixed endpoints, a GraphQL server exposes a single typed schema, and clients send queries that select exactly the fields they need. The server resolves each field and returns a response shaped precisely like the request.

Facebook built it in 2012 to solve a mobile problem: REST endpoints returned too much or too little data, and fetching a screen’s worth of related information meant many round trips. GraphQL fixed both by letting the client describe its data requirements in one document.

The schema

The schema is the contract. It defines the types and the operations available.

# schema.graphql
type User {
  id: ID!
  name: String!
  email: String
  posts(first: Int = 10): [Post!]!
}

type Post {
  id: ID!
  title: String!
  body: String!
  author: User!
}

type Query {
  user(id: ID!): User
  posts(limit: Int): [Post!]!
}

type Mutation {
  createPost(input: CreatePostInput!): Post!
}

The ! marks a field as non-null. Types compose into a graph, which is why a single query can walk from a user to their posts and back to authors. The schema is introspectable, so tooling can generate documentation, types and autocompletion automatically.

Queries

A query selects fields from the root query type, with arguments and variables.

# posts.graphql
query RecentPosts($limit: Int!) {
  posts(limit: $limit) {
    id
    title
    author {
      name
    }
  }
}

The response mirrors the selection exactly: no extra fields, no missing ones. Variables keep queries reusable and let the server validate argument types. Fragments extract repeated selections for reuse.

# fragment.graphql
fragment PostCard on Post {
  id
  title
  author { name }
}

query Feed {
  posts { ...PostCard }
}

Mutations and subscriptions

A mutation changes data and returns a defined shape, often including the updated object so the client can update its cache.

# create.graphql
mutation CreatePost($input: CreatePostInput!) {
  createPost(input: $input) {
    id
    title
  }
}

A subscription streams real-time updates over a persistent connection, such as new messages or live notifications. Use it when the server must push to the client; for occasional refreshes, polling or a refetch is simpler.

Resolvers

Resolvers are where the schema meets your data. Each field has a resolver that returns its value.

// resolvers.js
const resolvers = {
  Query: {
    user: (_parent, { id }, { db }) => db.users.findById(id),
    posts: (_parent, { limit = 10 }, { db }) => db.posts.findMany({ limit }),
  },
  User: {
    posts: (user, { first }, { db }) =>
      db.posts.findMany({ where: { authorId: user.id }, limit: first }),
  },
  Mutation: {
    createPost: (_parent, { input }, { db }) => db.posts.create(input),
  },
};

The context object carries shared resources such as the database and the authenticated user. Resolvers should be small, and authorization checks belong here or in the service layer they call — never on the client.

The N+1 problem

The most common GraphQL performance trap is N+1 queries. If a query returns ten posts and each post’s author resolver hits the database, you run eleven queries.

DataLoader solves it by batching and caching calls within a single request.

// loaders.js
import DataLoader from "dataloader";

function createUserLoader(db) {
  return new DataLoader(async (ids) => {
    const users = await db.users.findByIds(ids);
    return ids.map((id) => users.find((u) => u.id === id));
  });
}

The author resolver then calls loaders.user.load(post.authorId), and DataLoader collects all the loads in the tick into one query. This is the single most important optimisation in a GraphQL server.

Clients and caching

Client libraries such as Apollo Client and urql provide caching, normalisation, loading and error state, and integration with UI frameworks. A normalised cache stores entities by type and id, so a mutation that returns an updated post automatically updates every query that referenced it.

Because GraphQL typically uses a single POST endpoint, HTTP caching is less effective than with REST. Clients compensate with normalised caches, and servers use persisted queries and response caching. Design your mutations to return the changed objects so the client cache can stay consistent.

GraphQL or REST?

GraphQL shines when:

  • Clients need different fields for different screens.
  • A screen needs data from many related resources.
  • You want a single, typed, self-documenting API.

REST is simpler when:

  • Resources map cleanly to endpoints.
  • HTTP caching and status codes matter.
  • The API is small and stable.

Many teams run both, using GraphQL for the product API and REST for webhooks, file uploads and simple public endpoints.

Best practices

  • Design the schema around the client’s needs, not the database tables.
  • Use non-null types deliberately and version the schema with deprecations.
  • Keep resolvers thin and push logic into services.
  • Solve N+1 with DataLoader from the start.
  • Add query depth and complexity limits to prevent abuse.
  • Return changed objects from mutations for cache consistency.
  • Use persisted queries in production to reduce payload size.

Common mistakes

  • Exposing the database schema directly as the GraphQL schema.
  • Ignoring N+1 until performance collapses.
  • Fetching everything in every query and losing the main benefit.
  • Trusting client-supplied authorization or field-level permissions.
  • Building deeply nested queries with no depth limit.
  • Assuming HTTP caching works the same as with REST.

Where to go next

GraphQL is a powerful way to shape APIs around clients. Ground it in the HTTP protocol, build the server on Node.js, and consume it from React with a client library. Then model a screen you know well as a schema and query, and see how naturally the data requirements map.

Requesting data

GraphQL returns exactly the selected fields. REST endpoints often return far more than the client needs, wasting bandwidth and parsing time.

Prefer
query {
  user(id: "1") {
    name
    avatar
  }
}
// only name and avatar
// cross the wire
Avoid
// GET /users/1 returns
// the entire user record,
// including fields the
// client never displays

Fetching related data

A single GraphQL query can traverse relationships, avoiding the multiple round trips a REST client would make.

Prefer
query {
  user(id: "1") {
    name
    posts(first: 3) {
      title
      comments { text }
    }
  }
}
Avoid
# three requests:
# /users/1
# /users/1/posts
# /posts/:id/comments

FAQ

Frequently asked questions

Keep learning

Related topics from the roadmap.

$ start learning

Ready to start learning GraphQL?

Our interactive tutorial walks you through GraphQL step by step — with quizzes and real code you can run in the browser.