---
title: GraphQL
description: Drop in a GraphQL schema and get a native API reference — one real page per operation and per type, in your sidebar and search.
---

Point Blume at a GraphQL schema and it generates a native API reference: one **real page per root field** — queries, mutations, and subscriptions — plus one **page per named type** (objects, input objects, enums, interfaces, unions, and custom scalars). Every page shows arguments, defaults, deprecations, and usage backlinks, alongside a generated example operation, code samples, and an interactive [Try it](#try-it-playground) panel. Because each page is a genuine Blume page, it gets its own URL, shows up in **site search** and `llms.txt`, and gets an Open Graph image — the same as any hand-written doc.

The reference is the `graphql()` adapter from `blume/reference`, listed under `reference` beside any [OpenAPI](/docs/references/openapi) or [AsyncAPI](/docs/references/asyncapi) adapters:

```ts blume.config.ts lineNumbers
import { defineConfig } from "blume";
import { graphql } from "blume/reference";

export default defineConfig({
  reference: [
    graphql({
      spec: "./schema.graphql",
      endpoint: "https://api.example.com/graphql",
    }),
  ],
});
```

That mounts the reference at `/graphql` (an overview page), with root fields at `/graphql/queries/<field>`, `/graphql/mutations/<field>`, and `/graphql/subscriptions/<field>`, and types grouped by kind at `/graphql/objects/<type>`, `/graphql/enums/<type>`, and so on.

The `spec` is either a path to a local file in your project or an `http(s)` URL, and accepts two formats:

- **SDL text** — a `.graphql` file with type definitions.
- **An introspection result** — the JSON produced by running the standard introspection query, either the raw `{ "__schema": … }` shape or the full `{ "data": { "__schema": … } }` response envelope.

The `endpoint` is the live GraphQL API URL. A schema, unlike an OpenAPI document, names no server — so the endpoint is what the Try it panel and the generated code samples target. Leave it off and the samples render with a placeholder URL readers replace.

The reference doesn't add a header tab on its own. To surface it, point a [navigation tab](/docs/content/navigation#tabs) at its route — this also scopes the reference sidebar:

```ts blume.config.ts
navigation: {
  tabs: [{ label: "GraphQL", path: "/graphql" }],
}
```

## Generated examples

Every operation page carries a complete, valid example operation — one variable per argument, typed off the schema, with a bounded-depth selection set over the return type — plus matching example variables and an example response that mirrors the same selection. Code samples show the exact HTTP request (a JSON `POST` of `{ query, variables }`) in each configured language:

```ts blume.config.ts lineNumbers
reference: [
  graphql({
    spec: "./schema.graphql",
    codeSamples: ["curl", "js"],   // built in: curl, js, python
  }),
],
```

## Type pages

Named types get their own deep-linkable pages, grouped by kind in the sidebar: fields and input fields with their types linked, enum values, union members, interface implementations, and a **Used by** section listing the operations that return or accept the type and the other types that reference it. Spec-defined scalars (`String`, `Int`, …) don't get pages; custom scalars do, including their `specifiedBy` URL.

## Multiple schemas

Each entry in `sources` renders one schema on its own route. A per-source `endpoint` overrides the adapter's:

```ts blume.config.ts lineNumbers
reference: [
  graphql({
    endpoint: "https://api.example.com/graphql",
    sources: [
      { label: "Public API", spec: "./schema.graphql" },
      {
        label: "Admin API",
        route: "/graphql-admin",
        spec: "./admin.graphql",
        endpoint: "https://admin.example.com/graphql",
      },
    ],
  }),
],
```

`spec` is shorthand for a single-entry `sources`. Schemas that need different display options go in separate `graphql()` adapters, each with its own `route`. Each source takes the same [per-source controls](/docs/references/openapi#per-source-indexing) as `openapi()`: `includeInSearch`, `includeInLlms`, `noindex`, and `seoDescriptionSuffix` (here the generated sentence names the query, mutation, or type — "Reference for the `pets` query in the GraphQL API.").

## Try it playground

Query and mutation pages render an interactive panel: edit the request body (the query and variables), point it at your endpoint or a custom URL, and send — the code samples update live so what you copy is byte-for-byte what was sent. Disable it with `playground: false`. Subscription pages show the generated operation and an example event instead: subscriptions run over a stateful transport (WebSocket or SSE) that the playground's single HTTP `POST` can't speak.

If your GraphQL API doesn't allow cross-origin requests from the docs site, route sends through a CORS proxy — a URL of your own, or `true` for the built-in `/_api-proxy` endpoint (which needs [server output](/docs/deployment#server-rendering): a host adapter such as `deployment: vercel()` from `blume/deploy`). The built-in proxy only forwards to origins your documented specs declare — each configured GraphQL `endpoint`, plus any absolute `servers[].url` from a documented [OpenAPI spec](/docs/references/openapi) — so a public docs deployment can't be aimed at other hosts. That makes `endpoint` required for a working proxy: without one, the proxy has no origin to allow for this reference and refuses every send (the build warns about this). The same body limit and response headers apply as for the [OpenAPI proxy](/docs/references/openapi#try-it-playground).

```ts blume.config.ts lineNumbers
reference: [
  graphql({
    spec: "./schema.graphql",
    endpoint: "https://api.example.com/graphql",
    playground: { proxy: true },
  }),
],
```

There is no Scalar counterpart for GraphQL: the [`scalar()`](/docs/references/scalar) embed reads OpenAPI and AsyncAPI documents only, so a GraphQL reference is always rendered natively.
