SQL Formatter & Beautifier
Turn unreadable one-line SQL into clean, indented, reviewable code.
Why formatting SQL matters more than formatting most code
SQL is unusual: it is read far more often than it is written, and its readers are frequently not the author. A query written once during a feature launch gets read during an incident six months later, by someone with no context, at speed. Unformatted SQL makes that reading actively error-prone.
There is also a concrete mechanical benefit. Version control diffs are line-based. In a one-line query, changing one predicate rewrites the entire line, so the diff shows everything as changed and reviewers cannot see what you actually did. In formatted SQL, one clause per line means one changed line.
A before-and-after
-- Before: one line, 200 characters, unreadable
select u.id,u.email,count(o.id) as order_count,sum(o.total_cents)/100 as revenue from users u left join orders o on o.user_id=u.id and o.status<>'cancelled' where u.created_at>='2026-01-01' and u.deleted_at is null group by u.id,u.email having count(o.id)>3 order by revenue desc limit 50;
-- After: one clause per line, joins visible, intent obvious
SELECT
u.id,
u.email,
COUNT(o.id) AS order_count,
SUM(o.total_cents) / 100 AS revenue
FROM users u
LEFT JOIN orders o
ON o.user_id = u.id
AND o.status <> 'cancelled'
WHERE u.created_at >= '2026-01-01'
AND u.deleted_at IS NULL
GROUP BY u.id, u.email
HAVING COUNT(o.id) > 3
ORDER BY revenue DESC
LIMIT 50;
The second version takes more vertical space and is unambiguously better. You can
see the join condition, you can see which predicate belongs to the join and which to
the filter, and you can see that HAVING applies after
GROUP BY.
Conventions worth adopting as a team
Uppercase keywords, lowercase identifiers
Write SELECT, FROM, WHERE in uppercase and
table/column names in lowercase. This makes the structure of the query legible at a
glance and survives syntax highlighting being unavailable — in a code review comment,
a Slack message, or a terminal.
One major clause per line
Put SELECT, FROM, WHERE,
GROUP BY, HAVING, ORDER BY and
LIMIT each on its own line. Indent their contents one level. This is the
single highest-value rule.
Put join conditions on their own lines
ON clauses with multiple conditions should be split across lines. The
most common SQL bug in practice is a join predicate accidentally placed in
WHERE, which silently converts an outer join into an inner join. Making
the distinction visible prevents it:
-- Correct: filter belongs to the join, unmatched rows survive
LEFT JOIN orders o
ON o.user_id = u.id
AND o.status = 'paid'
-- Bug: this silently turns the LEFT JOIN into an INNER JOIN
LEFT JOIN orders o ON o.user_id = u.id
WHERE o.status = 'paid'
Alias every table, qualify every column
In multi-table queries, prefix every column with its alias. Six months from now,
nobody knows whether id means u.id or o.id —
and if a column is later added to both tables, the query breaks with an ambiguity
error.
Trailing commas, not leading
Use trailing commas at the end of each selected column. SQL, unlike JavaScript,
generally does not tolerate a trailing comma before FROM — so placing
commas at line end keeps the last column clean and makes diffs additive.
Formatting does not fix performance
A beautifully formatted query can still be catastrophically slow. Formatting improves
readability; it says nothing about execution. When a query is slow, the tools that
matter are EXPLAIN and EXPLAIN ANALYZE, which show you the
actual plan.
The highest-impact structural checks:
- Is there an index supporting each
WHEREpredicate and eachJOINkey? - Are you selecting columns you do not need?
SELECT *prevents index-only scans and breaks when the schema changes. - Is a function wrapping an indexed column —
WHERE DATE(created_at) = …— which makes the index unusable? Rewrite as a range comparison. - Is a
LIKE '%term'leading-wildcard scan running against a large table? Those cannot use a standard B-tree index.
A note on this formatter
Dialects differ, and a formatter tokenises rather than fully parses, so deeply nested CTEs, window functions and vendor-specific syntax may occasionally indent in a way you would not choose by hand. Always read the output before committing it. The formatter is a starting point, not an oracle — and for anything destined for production, the query plan matters far more than the indentation.
Frequently asked questions
No. Whitespace is insignificant to the SQL parser, so formatting changes readability only. Execution depends on the query plan, which you inspect with EXPLAIN.
No. All formatting happens in JavaScript in your browser. Nothing is logged or transmitted, so it is safe to paste queries containing real table and column names.
The keyword set covers standard SQL plus common PostgreSQL, MySQL and SQLite constructs: CTEs, window functions, joins, INSERT … ON CONFLICT, RETURNING. Highly vendor-specific syntax may format imperfectly — always review the result.
It is the dominant convention and makes structure readable without syntax highlighting. The more important thing is consistency within a codebase. Uncheck the box if your team prefers lowercase.
A predicate on the right-hand table placed in WHERE rather than in ON filters out the NULL-extended rows, converting the outer join into an inner one. Move the condition into the ON clause.