How to Format SQL: A Practical Guide to Beautifying Queries with an Online SQL Formatter
Format SQL in your browser: uppercase keywords, put each clause on its own line, indent JOINs and subqueries, and turn a one-line ORM query into readable code.
How to Format SQL: A Practical Guide to Beautifying Queries
A SQL query that runs fine and a SQL query you can read are two different artifacts. The database does not care about whitespace, casing, or where a JOIN sits. A human reviewer cares about all three. Most of the SQL I deal with arrives in the worst possible shape: a single 600-character line dumped by an ORM, or a 400-line monster exported from a BI dashboard with no breaks at all. Before I can review it, I have to format it.
This guide walks through what "formatting SQL" actually means clause by clause, shows a real before-and-after, and explains why doing it in a browser tab beats installing a CLI for most quick jobs. You can follow along in the SQL Formatter, which runs entirely client-side.
What Beautifying a Query Really Means
Beautifying is not cosmetic noise. A well-formatted query encodes its own structure visually. Three rules carry most of the weight:
- Keywords go UPPERCASE.
SELECT,FROM,WHERE,JOIN,GROUP BY,HAVING,ONall become uppercase so they stand out from table and column names. When the reserved words shout and your identifiers stay quiet, the eye separates grammar from data instantly. - Each clause sits on its own line. A new line for every major keyword turns a paragraph into an outline. You can scan the left edge and read the shape of the statement without parsing a word.
- Nested selects are indented. A subquery is a query inside a query, so it gets pushed one level to the right. The indentation literally draws the nesting depth, which is the single hardest thing to track in a wall of text.
Apply those three and a query stops being a string and starts being a structure. A good formatter does this deterministically, the same way every time, which is exactly what you want when several people touch the same migration files.
Indenting JOINs and Subqueries
JOINs are where readability lives or dies. A flat list of five joined tables with their ON conditions glued to the same line is unreadable. Formatted properly, each JOIN starts a fresh line aligned with FROM, and its ON predicate indents underneath. Now you can run your finger down the join list and check every key one at a time, which is how you catch the classic bug of joining on the wrong column.
Subqueries follow the same logic but with depth. A SELECT inside a WHERE ... IN (...) or an EXISTS (...) gets indented as a block, so the inner query reads as a self-contained unit rather than bleeding into the outer clause. Common Table Expressions in a WITH clause are the extreme case: each CTE is a named block, and a good layout keeps the WITH, the CTE bodies, and the final SELECT visually distinct so you can review them top to bottom like chapters.
A note on layout style. The "Tabular Left" option aligns major keywords to a fixed left column, which is great for flat scripts but can look strange on deeply nested CTEs. For heavy nesting, switch to "Standard" block indentation so each level steps cleanly to the right.
A Worked Example
Here is the kind of one-liner an ORM or a quick copy-paste hands you. It works, but reviewing it is painful:
select u.id, u.email, count(o.id) as orders from users u join orders o on o.user_id = u.id where u.created_at > '2026-01-01' and o.status in (select status from valid_statuses where active = 1) group by u.id, u.email having count(o.id) > 3 order by orders desc;
Run it through the formatter with keyword case set to UPPER and 2-space indent, and it unfolds into this:
SELECT
u.id,
u.email,
COUNT(o.id) AS orders
FROM
users u
JOIN orders o ON o.user_id = u.id
WHERE
u.created_at > '2026-01-01'
AND o.status IN (
SELECT
status
FROM
valid_statuses
WHERE
active = 1
)
GROUP BY
u.id,
u.email
HAVING
COUNT(o.id) > 3
ORDER BY
orders DESC;
Same query, same result set, zero logic changed. But now the join condition is on its own line, the IN subquery is a clearly indented block, and every clause announces itself down the left margin. The first version takes thirty seconds of squinting to understand. The second takes three.
Making an ORM-Dumped Query Readable
Most of my SQL reviews start with a log line, not a .sql file. Hibernate, Prisma, and friends emit queries as one unbroken string with machine-generated aliases like t0, t1, t2. The first time I hit a slow-query log full of those, I genuinely thought the schema was broken. It was not. The query was fine; the formatting was hostile. I pasted the 600-character line into the formatter, picked the right dialect, and the nested EXISTS and the WHERE predicates fell into place. Within twenty seconds I could see the missing index on t2.user_id that the wall of text had been hiding. That single habit, format first then read, has saved me more debugging time than any clever query rewrite.
The dialect choice matters here. Keyword lists and identifier quoting differ between engines, so formatting BigQuery's QUALIFY or a backtick-quoted project.dataset.table under ANSI mode will trip the parser. Match the dropdown to your actual database before you format.
Why Local Processing Matters
Production queries carry real schema names, table names, and sometimes sample PII baked into literal values. Pasting that into a random web service is a quiet data leak. A formatter that runs fully in the browser sidesteps the problem entirely: the query is parsed and pretty-printed in your tab using a JavaScript library, with no API call and no logging of the content. You can open DevTools, switch to the Network panel, and watch zero outbound requests fire while you format. That means you can clean up an internal migration file without it ever touching a third-party server.
One caveat worth repeating: because the current query is stored in the page URL so a shared link reproduces the exact result, avoid pasting live credentials or secret literals if you plan to share that link.
Fitting It Into Your Workflow
Formatting is a small step that pays off everywhere. Standardize keyword casing across a 30-file migration so the diff shows real schema changes instead of select versus SELECT noise. Clean up snippets before they go into a runbook. Make a code-review query legible before you ask a teammate to read it.
And formatting has a mirror image. When you are done reviewing and want to ship a query as a compact single line for a config file or an inline string, the SQL Minifier strips the whitespace back out. Beautify to read, minify to ship — two ends of the same workflow, both running locally in the browser.
Open the SQL Formatter, paste your ugliest one-liner, and see the structure appear.
Made by Toolora · Updated 2026-06-13