A SQL formatter sounds like a parser. It rarely is. Ours applies five
regex rules in a fixed order, and knowing that order tells you when the
output is trustworthy and when it quietly changes what you wrote. Here
is the pipeline, rule by rule, with the places it bites.
The five rules, in the order they run
Rule one collapses all runs of whitespace into single spaces. Your
newlines, your aligned columns, your indentation, all of it flattens
first.
Rule two walks a list of 45 keywords, from SELECT and FROM through
CASE, WHEN, and VIEW, and rewrites each word-boundary match to the
casing you chose. Uppercase is on by default.
Rule three inserts a line break before each of 24 major clause
starters, including SELECT, WHERE, the five join phrasings, ORDER BY,
GROUP BY, HAVING, INSERT INTO, UPDATE, DELETE FROM, LIMIT, and OFFSET.
Rule four indents. Lines that begin with a major clause sit at the
left margin. Every other line gets indented by your chosen width, 2
spaces by default or 4 if you prefer.
Rule five, on by default, gives AND and OR their own indented lines.
Feed it this one-liner:
SELECT u.id, u.name, o.total FROM users u INNER JOIN orders o ON u.id = o.user_id WHERE u.active = 1 AND o.total > 100 ORDER BY o.total DESC LIMIT 50
And the pipeline returns:
SELECT u.id, u.name, o.total
FROM users u
INNER JOIN orders o
ON u.id = o.user_id
WHERE u.active = 1
AND o.total > 100
ORDER BY o.total DESC
LIMIT 50
The ON clause indents under the join it belongs to. The AND hangs under
its WHERE. That structure is the entire value of the tool, and it comes
from rules three, four, and five working together.
One subtlety in rule three explains some odd output you may have seen.
The plain keyword JOIN runs before the phrase LEFT JOIN, so the words
first split apart, then the multiword rule rejoins them on a fresh
line. The end result is correct. The intermediate state is why you
sometimes see LEFT dangling for a moment in similar tools.
Where the regexes bite
A regex formatter does not know that quotes start a string literal.
This produces three failure modes you should check for every time.
String contents get rewritten. Rule one collapses whitespace inside
literals, so a value written with double spaces loses them. Rule two
recases keywords inside literals, so the value select your plan in
quotes becomes SELECT your plan. If your query compares against text
that contains SQL words or unusual spacing, verify the literal before
you run the formatted query anywhere.
AND inside BETWEEN gets split. Rule five has no context. The
condition BETWEEN 1 AND 5 becomes two lines, because the AND there is
indistinguishable from a logical AND to a regex. The query still runs.
It just reads wrong around every range filter.
CTEs and window functions stay flat. The keyword lists contain 45 and
24 entries, and WITH, OVER, and PARTITION BY are on neither. A query
built from CTEs formats its SELECT and WHERE clauses but never breaks
a line for the CTE boundaries, and dense window function arguments
remain one long line.
Subqueries also stay at one indent level. Rule four knows two states,
clause starter or continuation. It has no notion of nesting depth, so a
subquery in a FROM clause indents exactly like a column list.
Run it with a fixed routine
1. Paste the raw query into the input box.
2. Set the indent to match your team convention, 2 or 4 spaces.
3. Leave keyword uppercasing on unless your style guide says otherwise.
4. Press format.
5. Scan the output for the three bites above, in order. Check string
literals first, then any BETWEEN, then CTE and window clauses.
6. Turn off the AND/OR line break if your WHERE clauses are short. One
condition split across two lines costs more vertical space than it
returns in clarity.
7. Copy, and paste into your actual work.
What this SQL formatter is not
It does not parse SQL, so it does not validate anything. A query with a
syntax error formats as confidently as a correct one.
It is dialect blind. The rules speak generic SELECT, INSERT, UPDATE,
DELETE, and DDL. Vendor-specific clauses outside the keyword lists pass
through unformatted.
The formatting happens entirely in your browser. Nothing is sent to a
server, which matters if you paste a query containing table names or
business logic you would rather keep internal. The tradeoff is that the
tool also cannot store team presets, so you set your indent choice each
session.
For review, teaching, and PR readability, regex formatting covers most
of what you need. For migration scripts where literals must survive
byte for byte, use a parser based formatter instead, and diff its output
against the original.
Checklist before you copy formatted SQL
1. Diff the string literals against the original, spacing and case.
2. Find every BETWEEN and check whether its AND got split.
3. Check CTE and window function blocks that may not have broken lines.
4. Confirm the indent matches the file you are pasting into.
5. Never treat a formatted query as a validated query. Formatting and
correctness are unrelated.
---
Which query shape did a formatter break for you, a literal with double
spaces or an AND in the wrong place? Those stories are exactly the
cases worth collecting before anyone trusts a tool blindly. Run your
query through the five rules described here:
https://webrecast.com/en/sql-formatter