GraphQL Formatter

Paste a query copied out of a network tab, a mutation buried in a JavaScript string, or a full SDL schema, and read it back with proper nesting. The document is tokenized the way a GraphQL parser reads it, so strings, descriptions, and directives survive the trip.

Source

0 B

Formatted

0 B

Load a sample or paste your own document.

0Definitions
0Fields
0Max depth
0%Size change
Load a document

Commas are whitespace in GraphQL, so indentation carries the meaning

GraphQL treats commas as insignificant. The grammar lists them alongside spaces and tabs, which is why {id name email} and {id, name, email} parse to the same document. Fields have no separator of their own and no terminator either. Nesting is the only thing telling you which selection belongs to which parent.

Strip the line breaks and the document still runs. It stops being readable. A query copied from the Network tab of your browser arrives as one long line, a query pulled out of a template literal arrives with the indentation of the JavaScript file rather than of the query, and a schema pasted from a chat message arrives with whatever the client did to it. This page rebuilds the shape.

The parsing here is a tokenizer, not a regular expression sweep. That distinction shows up the moment your document contains something with braces inside a string:

Inputone line
mutation{search(q:"a { b }" ,first:5){id title}}
Outputformatted
mutation {search(q: "a { b }", first: 5) {id
title}}

The braces inside "a { b }" are string content, so they never touch the indent counter. Formatters built on find and replace break on that input, indenting the rest of the document one level too deep from the point the string appears.

What the printer changes, and what it leaves alone

Formatting is a rewrite of whitespace and punctuation only. No field is added, removed, renamed, or reordered, so the formatted document sends the same request as the one you pasted.

You pasteYou getReason
user(id:$id,first:10)user(id: $id, first: 10)Arguments stay on one line with a comma between them, which is how nearly every GraphQL codebase writes them.
...on Admin... on AdminAn inline fragment gets a space, a named spread like ...UserParts does not.
id ,, name ,id and name on two linesStray commas between fields are whitespace, so they are dropped rather than preserved.
posts: [Post!]!posts: [Post!]!Type expressions never break across lines. Non null and list markers sit tight against the type.
A """description"""Re-indented to the field below itBlock string content is dedented to the shortest common indent, then rewritten at the depth of the thing it documents.
# a noteIts own line, or goneComments are kept on their own line while the checkbox is ticked. Compact output drops them, since the wire has no use for them.
@include(if:$x)@include(if: $x)Directives print after the field they attach to, arguments spaced the same as any other argument list.

Max depth is the number your server watches

Public GraphQL endpoints reject queries past a depth limit, usually somewhere between 7 and 15. The reason is cyclic types. A User has posts, a Post has an author, and that author has posts again, so a short document nests far enough to make the resolver walk a large chunk of the database. Depth limiting is the cheapest defence, which is why it is the one most servers ship.

The depth counter above reads the formatted output. Every opening brace adds a level, so an operation body starts at 1 and each nested selection set adds one more. Relay style connections inflate it fast, because edges and node each take a level before you reach a real field:

1query {
2  viewer {
3    repositories(first: 10) {
4      edges {
5        node {
6          issues(first: 5) {

Six levels in, and the query has fetched nothing but wrappers. If an endpoint returns a depth error and the query looks short to you, format it here and read the counter before rewriting anything. Splitting one deep operation into two shallower ones is the usual fix.

Compact output is for the wire, not for your editor

Switch Output to Compact and the same document comes back on a single line with comments removed and spacing cut to the minimum the grammar accepts. Two situations call for it. Sending a query as a URL parameter on a GET request, where browsers and proxies start truncating somewhere around 2,000 characters. And registering a document in a persisted query store, where the hash has to match byte for byte across every client.

The size change counter reports the raw byte difference. Treat it as a rough figure rather than a saving. Every transport worth using applies gzip or brotli, and repeated indentation compresses close to nothing, so a 40 percent drop in raw bytes is often a couple of percent on the wire. Compact mode earns its place through length limits and hash stability, not through bandwidth.

One thing compact output keeps is block strings. A """ string preserves its own line breaks as content, so collapsing it would change the value being sent.

This page reads syntax, not your schema. Nothing here knows what types your API defines. A query asking for usre instead of user formats cleanly, because the misspelling is a valid field name as far as the grammar is concerned. The same goes for a wrong argument name, a variable declared and never used, or a fragment spread on a type it does not apply to. Those need a schema to catch, which means your IDE plugin, a GraphQL client with introspection loaded, or the server itself. Format here, validate there.

The errors this page does report

Structural problems surface with a line and column, and the Open that line button puts the cursor on them. Three account for most of what people paste:

Load the missing brace sample to see the shape of the report.

When another page fits the job better

Reach for this one when you have a document in hand and want it readable. If you are going the other way, turning a JSON payload into type definitions, the GraphQL schema generator starts from the data. If what you have is the response rather than the request, a GraphQL reply is ordinary JSON under an outer data key, so the JSON beautifier or the API response formatter is the page that will parse it. Pasting a response here reports an unexpected character on the opening brace of the JSON object, since GraphQL has no syntax for a quoted key.

Questions that come up with a real document open

What people ask once a query, a schema, or an error is in front of them.

Does formatting change what my query returns?

No. Only whitespace, commas, and comment placement move. Field names, arguments, aliases, variables, directives, and their order come through untouched, so the formatted document requests exactly what the original did. Comments are the one thing that disappears, and only when you untick the checkbox or switch to compact output.

Why does my query format but still fail on the server?

Formatting checks the grammar. It has no idea which types your API defines, so a misspelled field, an argument the schema does not accept, or a fragment on the wrong type all format cleanly and fail at execution. Validation needs the schema, which means an IDE plugin with introspection or the endpoint itself.

Does it handle SDL as well as operations?

Yes. Type, interface, input, enum, union, scalar, schema, directive, and extend definitions all print, along with implements lists, default values, and repeatable directives. Descriptions written as block strings are dedented and re-indented above the field they document.

Is my document sent anywhere?

No. The tokenizer and printer are JavaScript running in this tab, and the editors hold everything in browser memory. A schema from a private API stays on your machine, and nothing persists once you close the tab, so save what you want to keep.

What happened to my commas?

GraphQL counts commas as whitespace, so the parser ignores them wherever they appear. They are removed between fields, where they add nothing, and written between arguments, where nearly every codebase uses them. That matches the output of the reference printer in graphql-js.

Can I format a query that lives inside a gql template literal?

Paste the text between the backticks, not the backticks themselves. A stray backtick is not a GraphQL character and gets reported as unexpected. Interpolations such as ${FRAGMENT} fail for the same reason, so replace them with the fragment text or remove them before formatting.

Why is my max depth higher than the number of fields I asked for?

Connection wrappers count. A Relay style pattern spends a level on edges and another on node before reaching anything real, so a query that looks two deep to you reads as four to a depth limiter. The counter above reflects brace nesting in the formatted output.

Does compact output produce the same hash every time?

For the same input, yes. The printer is deterministic, so the byte output is stable across runs. Two documents differing only in whitespace collapse to identical compact text, which is what persisted query registration depends on. Field order still matters, since reordering fields produces a different document.