Paste or upload GraphQL and format it into a clean, readable .GRAPHQL file in seconds—no installs needed.
graphql-js's print() emits, and what the official GraphQL Playground / GraphiQL examples use), 4 spaces (matches Python tooling and some Java schemas), or Tab (rare in GraphQL, but supported for codebases that enforce tabs everywhere). The selection drives indentation for nested selection sets, argument lists, and input-object literals..graphql (schema) or .gql (query) file. Everything runs in your browser — no upload, no sign-up, no server log of your operation text or schema.GraphQL is a strict-grammar language, but the official spec treats whitespace, line breaks, and commas as insignificant — so the same document can be written as a one-line dense string or as a 200-line nested tree, and both are valid. That flexibility means GraphQL extracted from network traces, Apollo gql template literals, or persisted-query manifests often arrives unreadable. Formatting parses the document, throws away the original whitespace, and re-emits canonical layout. Common scenarios where this matters:
graphql-request all serialize operations to a single line before sending. Pasting the raw operation from the browser Network tab into a formatter restores indentation so you can see exactly which fields and fragments your component asked for. Pair with JSON Formatter when you also need to read the response body.schema.graphql only diff cleanly when types, fields, and arguments each sit on their own line. Auto-formatting before commit is why Prettier's GraphQL parser ships as a first-class language and not a plugin (it has been built in since Prettier 1.5, released June 2017).implements Node & Timestamped), and directive applications that are otherwise hidden in run-on text.| Operation kind | Keyword | What it does | Where it appears |
|---|---|---|---|
| Query | query (or anonymous shorthand) |
Read-only field selection | Executable documents — most client traffic |
| Mutation | mutation |
Write operation; server may execute fields serially | Executable documents — form submits, state changes |
| Subscription | subscription |
Long-lived stream over WebSocket or SSE | Executable documents — live updates |
| Fragment definition | fragment Name on Type |
Named reusable selection set | Executable documents — colocated with components |
| Inline fragment | ... on Type |
Type-conditional selection inside another selection set | Inside any operation — for union / interface refinement |
| Type definitions | type, interface, union, enum, input, scalar |
Schema-side type declarations | SDL documents (schema.graphql) |
| Extensions | extend type, extend schema |
Add fields / values to an existing type, typically across modules | SDL documents — common in Apollo Federation and modular schemas |
The formatter handles all of the above with the same grammar — the GraphQL spec, Section 2 — Language defines one syntax shared by executable and type-system documents. Mixing a type definition into a file alongside a query parses fine; both get pretty-printed identically.
| Tool | What it is | Where you'd use it |
|---|---|---|
graphql-js print() |
The reference printer in the graphql-js reference implementation. Takes a parsed AST and emits canonical 2-space-indented SDL. | Programmatic formatting inside Node tooling, codegen, schema-stitching libraries. |
| Prettier (built-in GraphQL parser) | Industry-standard code formatter; the graphql parser ships in the main package, no plugin required. |
Editor save-on-format, lint-staged pre-commit hook, CI formatting check. Handles .graphql files and gql / graphql tagged template literals in JS / TS. |
| Apollo Studio / Apollo Sandbox | Apollo's web IDE applies its own formatter when you click the "prettify" button. | Exploring a remote schema; quick one-off cleanup of an operation pasted from logs. |
| GraphiQL "Prettify" | The official reference IDE has a built-in prettify command bound to Shift-Ctrl-P / Shift-Cmd-P. | Local development against a running GraphQL endpoint. |
gajus/format-graphql (npm) |
A CLI wrapper around graphql-js that also sorts type and field names alphabetically. |
When you want a deterministic, diff-friendly schema with sorted members (rare in production but useful for review). |
| xconvert GraphQL Formatter (this page) | Browser-side formatter — paste, pick indent, copy. No install. | One-off cleanup of an operation from a network trace, sharing a tidy snippet on Slack, fixing indentation on a schema before pasting it into a doc. |
The functional output across these is nearly identical for valid GraphQL — they all parse to an AST and re-emit canonical layout. Differences show up in error messages, in whether comments survive a round-trip (most printers drop # comments because the GraphQL spec marks them as insignificant), and in optional extras like alphabetical sorting.
.graphql and .gql files natively?Yes — since Prettier 1.5 (June 28, 2017). The GraphQL parser is built into the main prettier package, so prettier --write schema.graphql and prettier --write 'src/**/*.{graphql,gql}' work out of the box with no extra plugin. Prettier also formats GraphQL inside JavaScript and TypeScript template literals tagged with gql, graphql, or graphql.experimental, which is what Apollo Client, Relay, and graphql-tag use. If you want stricter rules layered on top of Prettier formatting, the @graphql-eslint/eslint-plugin package adds lint rules that complement (rather than fight) Prettier's whitespace decisions.
Yes. The GraphQL spec, Section 2 defines one grammar that covers both executable documents (queries, mutations, subscriptions, fragments) and type-system documents (type, interface, union, enum, scalar, input, directive, extend). The same lexer and parser handle both, and graphql-js's print() emits the same conventions for both: one definition per block, 2-space nested indentation, multi-argument lists wrapped when the inline form gets long, descriptions (block strings) immediately above their target. A formatter that gets queries right will get schemas right; conversely, no special "SDL mode" is needed.
Inline fragments use the ... on TypeName syntax and appear inside another selection set, usually to refine a union or interface field. The formatter places the spread on its own line, indents the conditional selection set one level deeper than the parent, and aligns the closing brace with the spread. For example, a search field returning a union of User | Article formats as search { ...on User { name } ...on Article { title } } re-emitted with each ... on on its own line. Anonymous spreads without a type condition (just ... { ... }, used to apply a directive to a group of fields) format the same way — the directive sits on the spread line and the selection set follows.
@deprecated formatted?Directives attach to the token they decorate (field, argument, type, enum value) and emit on the same line as that token. The widely followed convention — applied by graphql-js's print() and Prettier — is to place auth and validation directives first (@auth, @hasRole, @requiresScope), then transformation directives (@formatDate, @upper), then @deprecated last because it is state-of-the-field metadata rather than a transformation. The formatter preserves whatever order you wrote in the source; if you want re-ordered directives, layer an opinionated linter (@graphql-eslint, format-graphql) on top. For multi-argument directives like @deprecated(reason: "Use newField instead"), the argument list follows the same wrapping rule as field arguments — inline if short, one argument per line if long.
Yes — the GraphQL spec marks commas as insignificant (the same category as whitespace). You can write users(first: 10, after: "abc",) with a trailing comma and the parser accepts it; you can also write the same call with no commas at all (users(first: 10 after: "abc")) and it parses identically. The formatter normalizes either form by dropping commas entirely in canonical output, which is what graphql-js and Prettier both do — commas are reserved for human-written shorthand, not for the canonical printed form. If you paste source with trailing commas, expect them to disappear after formatting; the document is semantically unchanged.
# comments?GraphQL comments use # and run from the # to the end of the line. The spec treats comments as insignificant — they are tokenized as Comment tokens and then ignored by the parser. As a result, most formatters (including graphql-js's print() and Prettier's GraphQL printer) drop comments on a round-trip because the AST does not carry them. The exception is descriptions: block-string descriptions ("""this field returns the user""") attached to types, fields, enum values, or arguments are first-class AST nodes and DO survive formatting. If you need to keep documentation through a format cycle, write it as a block-string description above the target rather than as an inline # comment. This is the same convention every public GraphQL schema uses (GitHub's, Shopify's, GitLab's).
extend type and modular schemas?Yes. extend type User { ... }, extend interface Node { ... }, extend schema { ... }, and the union / enum extension forms are all part of the GraphQL type-system grammar and parse identically to their non-extend counterparts. The formatter emits each extend block on its own line with the same indentation rules as a base definition. This matters for Apollo Federation, schema stitching, and any modular-schema setup where types are declared in one file and extended in others — the formatter does not need to resolve the cross-file references; it formats each file's syntax in isolation. If you want flattened (resolved) SDL, use graphql-tools' mergeSchemas or buildSubgraphSchema first, then format the merged output.
graphql-js disagree?In practice they don't, but the GraphQL spec is the source of truth and the graphql-js reference implementation is what most tooling (Apollo Server, Yoga, Relay, urql, every major codegen, Prettier's GraphQL parser, and this formatter) builds on. Other implementations — graphql-java, juniper (Rust), graphql-go, gqlgen, Ariadne (Python) — sometimes lag the spec on newer features (e.g., the repeatable directive, OneOf input objects, the @specifiedBy directive) but they all follow the same parsing rules for the core grammar that this formatter cares about. If you hit a case where one implementation accepts input another rejects, default to the spec's behavior and file a bug against the lagging implementation.
No. Formatting runs entirely in your browser in JavaScript. The page loads once, then your query or schema stays local — no network request, no logging, no retention. Safe for operations that reference production resolvers, internal type names, or schemas under NDA. You can verify by opening DevTools' Network tab while formatting, or by disconnecting from Wi-Fi after the page loads — formatting still works. For related developer tools that also run client-side, see JSON Formatter, SQL Formatter, JS Formatter, and Text Diff for comparing two formatted documents.
Practically, anything up to a few megabytes formats in well under a second on a modern laptop — that covers nearly every real-world schema, including ones with thousands of types. The full GitHub public GraphQL schema (around 1 MB of SDL with descriptions) formats in roughly a second. Browser memory is the only hard limit; multi-megabyte machine-generated schemas may pause the tab briefly during parse. For repeated batch formatting (CI hooks, codegen pipelines), use prettier --write or a custom Node script that calls graphql-js's parse + print directly — both stream input and are faster for bulk work than any browser tool.