How to format SQL.
Without changing what it means.
A formatter rewrites whitespace. The skill is in the two places it must not touch — the case inside a quoted identifier and the contents of a string literal — and in the handful of conventions that make a long query readable.
Short answer: pick one keyword case and keep it; put every JOIN on its own line with its ON underneath; alias every table; and never let a formatter change the case inside "quoted identifiers" or 'string literals' — in PostgreSQL and standard SQL, "UserID" and "userid" are different columns. Tell the formatter which dialect you are writing in, because LIMIT, TOP and FETCH FIRST are the same operation spelled three ways.
Written by the Tool Pantry team on 22 October 2026. The dialect differences are the documented behaviour of PostgreSQL, MySQL and standard SQL; the code samples are ours. A formatter that does not parse the query first cannot tell syntax from data, which is the failure this guide is mostly about.
What a formatter does, and what it must never do
A SQL formatter rewrites whitespace: keyword case, indentation, line breaks around clauses. It does not change the query. The part that matters is the second half of that sentence — a formatter that alters case inside a quoted identifier, reorders a WITH clause, or rewrites a string literal has changed the query, not formatted it.
That is not a hypothetical. In PostgreSQL and in standard SQL, "UserID" is a different identifier from "userid" — the case inside the quotes is part of the name. Lowercasing it breaks the query, and the error arrives as "column does not exist" rather than "the formatter changed something". The same goes for string literals: 'Smith' is data, and a formatter that turns it into 'smith' has edited a customer’s name.
Keyword case: pick one and keep it
There is no correct answer. Uppercase keywords (SELECT, FROM) read as SQL rather than as English; lowercase (select, from) read as prose. Both are used in large codebases. The only wrong choice is a file with both.
One thing worth knowing: most editors and formatters can change only the keywords and leave identifiers and strings alone, because those are the parts the parser has marked. A formatter that does not distinguish them is going to bite you eventually, whatever its casing rule.
The dialect differences that catch people out
| What it does | PostgreSQL | MySQL | Standard SQL |
|---|---|---|---|
| Limit the rows | LIMIT 10 | LIMIT 10 | FETCH FIRST 10 ROWS ONLY |
| Quote an identifier | "name" | `name` | "name" |
| Join two strings | a || b | CONCAT(a, b) | a || b |
| Date literal | DATE '2026-01-31' | '2026-01-31' | DATE '2026-01-31' |
That is why the formatter here asks which dialect you are writing in: it changes how it quotes identifiers and how it treats the date and string syntax, not just the whitespace. SQL Server adds a fourth set of differences — TOP 10 instead of LIMIT, and square brackets for identifiers.
The join is where the readability is won or lost
Most unreadable SQL is not badly indented SQL, it is a query where six tables are joined and you cannot tell which condition belongs to which join. Putting each JOIN on its own line with its ON condition indented under it turns a wall into a list:
SELECT o.id, c.name, t.total
FROM orders o
JOIN customers c
ON c.id = o.customer_id
JOIN (
SELECT order_id, SUM(amount) AS total
FROM order_lines
GROUP BY order_id
) t
ON t.order_id = o.id
WHERE o.created_at >= DATE '2026-01-01'
ORDER BY t.total DESC;
Two habits do most of the work. Give every table an alias, and never leave a join without its ON on the line below it. Aliases also stop customer_id and shipping_customer_id from looking identical, which is where the real bugs live.
Long queries: break them where a human reads
Keep lines under about 100 characters, and break a SELECT list one column per line when there is more than a handful. A common and readable shape:
SELECT
o.id,
o.created_at,
c.name AS customer_name
FROM orders o
JOIN customers c
ON c.id = o.customer_id
WHERE o.status = 'paid'
Subqueries in the FROM clause, like the total above, are worth converting to a WITH block when they are reused or complicated. A WITH clause is not faster, but it gives a name to the thing you are computing, and the name is what the next reader needs.
Running it
The SQL formatter parses the query and rewrites it in the browser, with a dialect selector for standard SQL, PostgreSQL and MySQL. It shows the formatted result next to the original so you can see exactly what changed, and nothing leaves your machine — which matters more than it sounds, because a WHERE clause can hold a customer name, a phone number or an internal ID.
Two things to check after formatting a query you care about: that the row count is the same, and that the query still explains itself. Formatting is not a review, and a formatter will happily make a wrong query look tidy.
Should SQL keywords be uppercase or lowercase?
Either, as long as one file does not mix them. Uppercase reads as SQL, lowercase reads as prose. The part that is not a style choice is the case inside quoted identifiers and string literals: "UserID" is a different name from "userid" in PostgreSQL and standard SQL, and a customer's name in a literal is data, not syntax.
Can a SQL formatter change my query?
It should not, and the parts most likely to break are the case inside quoted identifiers, string literals, and the order of WITH clauses. A good formatter changes whitespace and keyword case only, and leaves the rest alone. The formatter here parses the query first, so it knows which parts are syntax and which are data.
What is the difference between SQL dialects?
The same operation is spelled differently: LIMIT 10 in PostgreSQL and MySQL against FETCH FIRST 10 ROWS ONLY in standard SQL, TOP 10 in SQL Server; double quotes for identifiers in PostgreSQL against backticks in MySQL; the || operator against CONCAT() in MySQL. Telling the formatter which dialect you are writing in avoids a rewrite that breaks the query.
How do I make a long query readable?
Break it where a human reads. One SELECT column per line when there are several, each JOIN on its own line with its ON condition indented under it, and an alias for every table so that customer_id and shipping_customer_id stop looking the same.
Is my SQL uploaded anywhere?
No. The formatter runs in your browser, so a WHERE clause with a customer name or an internal ID never leaves your machine.