01 — What it is

A GraphQL layer on top of WordPress.

WPGraphQL is a free, open-source plugin that adds an extendable GraphQL API to any WordPress site. Your post types, taxonomies, users, media and custom fields become one typed schema. The frontend sends a query to a single endpoint and gets back only the fields it asked for.

FrontendNext.js · app · widget
/graphqlone endpoint
SchemaPost · User · Term · Media
WordPressqueries · DB
01

One endpoint

Every read goes to /graphql. No list of routes to learn: the schema is the documentation.

02

Typed schema

Built from what your site already has. Plugins and your own code extend it with register_graphql_field.

03

Open source

GPL-3.0, installed from WordPress.org like any plugin. Extensions for the IDE, Smart Cache and ACF live in the same official repository.

02 — How it works

Ask for a shape. Get that shape back.

One post page needs the post, its author, categories and featured image. With default REST routes that is several requests or a heavy _embed. With WPGraphQL it is one query.

  1. QueryThe frontend describes the fields it needs and sends them to /graphql, as GET for public reads.
  2. ValidateWPGraphQL checks every field and type against the schema before anything touches the database.
  3. ResolveResolvers load the data. Built-in loaders batch related lookups by ID across the whole list.
  4. RespondJSON comes back in exactly the shape of the query: no extra fields, no second trip.
queryPostBySlug
query PostBySlug($slug: ID!) {
  post(id: $slug, idType: SLUG) {
    title
    date
    author { node { name } }
    categories { nodes { name slug } }
    featuredImage {
      node { sourceUrl altText }
    }
  }
}
response200
{ "data": { "post": {
  "title": "…",
  "date": "…",
  "author": { "node": { "name": "…" } },
  "categories": { "nodes": [ … ] },
  "featuredImage": {
    "node": { "sourceUrl": "…", "altText": "…" }
  }
} } }

03 — Examples

Three patterns you use from day one.

From our hands-on build: WPGraphQL + Next.js, step by step.

Cursor paginationgraphql
query Posts($first: Int!, $after: String) {
  posts(first: $first, after: $after) {
    pageInfo { hasNextPage endCursor }
    nodes { slug title date }
  }
}

Pass endCursor back as after. Cursors are opaque: build “Older / Newer”, not page numbers.

Custom fieldphp
add_action( 'graphql_register_types', function () {
  register_graphql_field( 'Post', 'readingTime', array(
    'type'    => 'Int',
    'resolve' => function ( $post ) {
      // words / 200, min 1
    },
  ) );
} );

Register once in WordPress, and every client can query readingTime.

Fragmentgraphql
fragment PostCard on Post {
  slug
  title
  date
  excerpt
  readingTime
}

The list, the single page and “related posts” share one shape. Change the card, edit one fragment.

>_

Query terminal · coming soon

Build a WPGraphQL query step by step, wizard style, and see the response shape before you write a line of frontend code.

04 — Where it’s used

Wherever WordPress is the content backend.

01

Headless frontends

Next.js with the App Router reads posts through server components and plain fetch. No client library needed for reads.

02

One WordPress, many channels

A site, a mobile app and an embedded widget query the same schema, each asking only for what it shows.

03

Blocks as components

WPGraphQL Content Blocks returns Gutenberg blocks as typed data, so each block type maps to your own component.

04

Custom fields

WPGraphQL for ACF exposes field groups with Show in GraphQL. Native meta goes through register_graphql_field.

05 — Benefits

Why developers reach for it.

1×

One request

Related types in a single round trip instead of a REST waterfall.

{ }

Exact shape

No over-fetching: each component asks for exactly what it displays.

T

Self-documenting

A typed schema you can explore in GraphiQL from the WordPress admin.

+

Extensible

register_graphql_field and register_graphql_type keep custom data consistent with core types.

⚡

Cacheable

GET plus persisted queries make public reads cacheable by URL, at the CDN and in Next.js.

06 — Challenges

Easy to start. Lock it before launch.

The default setup is developer-friendly, not production-safe. The flexibility that makes GraphQL attractive is also its biggest risk.

  • Introspection. Public introspection exposes the whole schema. Keep it off; logged-in developers still have GraphiQL.
  • Query depth. Turn on depth limiting with a max your real queries fit into.
  • Page size. Cap connections: graphql_connection_max_query_amount → 50.
  • Caching. A POST with a query body has no URL to cache on. Use GET + persisted queries.
  • N+1. A custom resolver that queries per node multiplies DB calls. Batch through loaders.
  • Schema sprawl. Two plugins adding the same field name to one type is a real conflict. Review names before launch.
  • Logic in resolvers. Keep resolvers thin and call the same service layer your REST endpoints use.

07 — FAQ

Questions we get about WPGraphQL.

Should a new headless project use GraphQL or REST?

GraphQL when pages routinely assemble several related content types and REST would mean several round trips or a heavy _embed. REST when most pages need one resource with light relations: it is simpler to build, cache and debug.

Should I send GraphQL requests as GET or POST?

GET for public reads, so responses are cacheable by URL. POST for mutations and authenticated requests.

Do I need Apollo Client or urql with Next.js?

Not for server components. Plain fetch with Next.js caching covers reads. A client library earns its place with heavy client-side state, optimistic updates or subscriptions.

Does WPGraphQL work with ACF?

Yes. Install WPGraphQL for ACF and enable Show in GraphQL on the field group. The fields appear on the post type in the schema.

Can I render Gutenberg blocks as React components?

Yes, with WPGraphQL Content Blocks: blocks come back as typed data instead of one HTML string, and you map each block type to a component.

How do I secure a public GraphQL endpoint?

Disable public introspection, enforce depth limits, cap page size and move to persisted queries, so the server only executes a known, approved set of queries.

WPGraphQL name, logo and brand colours © WPGraphQL contributors, used to refer to the project (GPL-3.0). 4wp.dev is an independent educational series, not affiliated with WPGraphQL. Primary source: wpgraphql.com.