GraphQL Formatter Guide: Format & Beautify GraphQL Queries
GraphQL Formatter Guide: Format & Beautify GraphQL Queries
GraphQL operations are easy to write on one line and painful to read on one line. A GraphQL formatter rewrites a compact query, mutation, or subscription into a readable, indented tree so you can see the selection set at a glance. Try it with our GraphQL Formatter — it runs entirely in your browser, and no operation text ever leaves your machine.
What Is a GraphQL Formatter?
A GraphQL formatter is a tool that takes a GraphQL operation string and rewrites it with consistent indentation, turning a dense single line into a structure that reads like a tree. Unlike a strict parser, it does not need to build a typed AST to make the document readable — a lightweight, bracket-based re-indenter is enough for most human inspection tasks.
The core operations are:
- Pretty-print — break the selection set across lines, adding 2 spaces of indentation per nesting level.
- Normalize whitespace — collapse runs of spaces and trim trailing whitespace on every line.
- Preserve semantics — field names, arguments, variables, and directives stay exactly as written.
Pretty-Print vs Minify
These are opposite layouts, and choosing the right one depends on where the query lives.
| Mode | Result | Use case |
|---|---|---|
| Pretty | Newlines + 2-space indent | Reading, code review, sharing in docs or tickets |
| Minify | One line, no spaces | Embedding in a curl call, HTTP logs, or a single-line transport |
Rule of thumb: pretty-print while reading and reviewing, keep it compact when pasting into a one-line transport like a URL, a log line, or a shell command.
How Bracket-Based Indentation Works
The formatter walks the string character by character. Three rules drive the layout:
{increases the indent level and starts a new line.}decreases the indent level and closes on its own line.,(and any existing newline) starts a new line at the current indent.
Whitespace between tokens is collapsed to a single space — except it is dropped right
after {, (, or another space, so user(id:$id){ stays tidy without inventing a
space that could change meaning.
query GetUser($id: ID!) {
user(id:$id) {
name
email
}
}
Code Examples
JavaScript
The browser tool uses this exact function (copied from the live formatter):
function formatGraphQL(query) {
const INDENT = " ";
let result = "";
let indent = 0;
let i = 0;
const len = query.length;
while (i < len) {
const ch = query[i];
if (ch === "{") {
indent++;
result += " {\n" + INDENT.repeat(indent);
i++;
} else if (ch === "}") {
indent = Math.max(0, indent - 1);
result += "\n" + INDENT.repeat(indent) + "}";
i++;
} else if (ch === "," || ch === "\n") {
if (ch === ",") result += ",";
i++;
result += "\n" + INDENT.repeat(indent);
} else if (ch === " " || ch === "\t") {
const prev = result[result.length - 1];
if (prev !== " " && prev !== "\n" && prev !== "{" && prev !== "(") {
result += " ";
}
i++;
} else {
result += ch;
i++;
}
}
return result
.split("\n")
.map((line) => line.trimEnd())
.join("\n")
.trim();
}
Python
The same bracket-based algorithm, reimplemented in Python:
def format_graphql(query: str) -> str:
INDENT = " "
result = ""
indent = 0
i = 0
n = len(query)
while i < n:
ch = query[i]
if ch == "{":
indent += 1
result += " {\n" + INDENT * indent
i += 1
elif ch == "}":
indent = max(0, indent - 1)
result += "\n" + INDENT * indent + "}"
i += 1
elif ch == "," or ch == "\n":
if ch == ",":
result += ","
i += 1
result += "\n" + INDENT * indent
elif ch == " " or ch == "\t":
prev = result[-1] if result else ""
if prev not in (" ", "\n", "{", "("):
result += " "
i += 1
else:
result += ch
i += 1
return "\n".join(line.rstrip() for line in result.split("\n")).strip()
For production pipelines that must understand arguments, fragments, and directives,
parse with a real GraphQL library (e.g. graphql in JS or graphql-core in Python)
and re-print from the AST. The heuristic above is ideal for quick, ad-hoc inspection.
Common Pitfalls
- Space-separated selections stay on one line. The formatter only breaks lines on
,and{. A query writtenname email posts { … }keepsname email poststogether — see the Hands-on section for proof. - Feeding already-formatted input leaves ragged output. Paste a multi-line, indented query and you get extra blank lines and double spaces, because the tool re-derives indentation from brackets rather than trusting your existing newlines.
- It is not a validator. Bracket re-indentation never checks that fields exist on the schema or that variables are declared. Use a linter or the schema for that.
- Arguments and directives are preserved verbatim.
(id:$id)and@include(if: $x)are kept exactly as typed; the tool will not reorder or pretty-print inside them.
Hands-on: Tested with the Tool
I ran the live GraphQL Formatter (the same code shown above) on three real inputs. The outputs below are copied exactly from the tool.
Test 1 — the tool's default compact query
Input:
query GetUser($id: ID!){user(id:$id){name email posts{title content comments{body author{name}}}}}
Output:
query GetUser($id: ID!) {
user(id:$id) {
name email posts {
title content comments {
body author {
name
}
}
}
}
}
Observation: the tree is now readable, but name email posts sit on a single line.
That is expected — without commas, the re-indenter has no signal to split sibling
selections, so it keeps them inline.
Test 2 — the same query with commas between fields
Input:
query GetUser($id: ID!){user(id:$id){name,email,posts{title,content,comments{body,author{name}}}}}
Output:
query GetUser($id: ID!) {
user(id:$id) {
name,
email,
posts {
title,
content,
comments {
body,
author {
name
}
}
}
}
}
Observation: every field now gets its own line because commas trigger a line break. If you want one field per line, add commas — both styles are valid GraphQL.
Test 3 — a mutation with a variable
Input:
mutation CreatePost($input: PostInput!){createPost(input:$input){id title status createdAt}}
Output:
mutation CreatePost($input: PostInput!) {
createPost(input:$input) {
id title status createdAt
}
}
Observation: the variable declaration $input: PostInput! and the argument
input:$input are preserved inline. The formatter only re-indents around braces; it
never rewrites token contents.
Quirk confirmed (Test 4) — pre-formatted multi-line input
Pasting an already indented, multi-line query produced stray blank lines and a double
space before some { characters, because the tool re-derives indentation purely from
brackets and treats your existing newlines as additional break signals. For the
cleanest result, paste the compact (minified) query — the formatter is built to take
compact input and expand it, not to tidy already-formatted source.
Related Tools
- Pretty-print nested JSON responses with the JSON Formatter.
- Turn a JSON sample into TypeScript interfaces with JSON to TS.
- Generate types and classes in many languages from JSON using JSON to Code.
- Format config in other languages with the YAML Formatter and XML Formatter.
- Validate JSON structure against a contract with JSON Schema Validator.
When to Use This Tool Instead of Code
You can pipe a query through a GraphQL codegen tool or prettier with the GraphQL
parser, but a browser formatter wins the moment you copy a query out of a network tab,
a chat, or a doc and just want to read it — no install, no package to trust with your
operation text. For repeatable, schema-aware formatting inside a build step, keep the
library; for ad-hoc inspection, use the tool. For the payload side of the same
request, our JSON Formatter guide explains
pretty-printing the response body.