SQL arrives in every shape: a one-line query copied from an ORM log, a join with four tables and no indentation, a migration with a nested subquery. A formatter turns that wall of text into clause-per-line SQL that a reviewer can scan. The important qualification is that a lightweight formatter is not a database parser. It recognizes a fixed keyword list, moves major clauses onto new lines and indents parentheses. It cannot know your dialect, validate syntax or run the query. Read the output before you paste it into a production console.
Part of the developer toolkit guide. Format in the SQL formatter, keep a copy of the original, and run the reviewed statement against a development database rather than trusting the layout alone.
What the formatter actually changes
The tool begins by collapsing every run of whitespace to a single space. It then protects single-quoted strings and double-quoted identifiers with placeholders, uppercases a fixed keyword list, and inserts a newline before major clauses such as SELECT, FROM, WHERE, GROUP BY, ORDER BY, JOIN, HAVING, LIMIT and UNION. AND, OR and ON begin new lines. Semicolons start a new line, and lines inside parentheses receive two spaces of indentation per level.
That is a useful clause-level layout, not a complete pretty-printer. It does not align equals signs, split a long select list into one column per line, uppercase every SQL word or add missing punctuation. Functions such as COUNT and modifiers such as DESC are outside its keyword list, so they keep the casing you typed. The Minify button goes the other way and collapses the whole statement to a single line.
The formatter has no database connection and no schema awareness. It cannot tell whether a name is a table, a column or a keyword in your dialect. It also does not validate the query. A missing comma stays missing after formatting, and a misplaced JOIN remains misplaced.
Clause layout and joins
Example 1 starts as one line: select u.id,u.name,count(o.id) as orders from users u left join orders o on o.user_id=u.id where u.active=1 and o.created_at>='2026-01-01' group by u.id,u.name order by orders desc limit 20;. Formatting produces this structure:
SELECT u.id,u.name,count(o.id) AS orders
FROM users u
LEFT
JOIN orders o
ON o.user_id=u.id
WHERE u.active=1
AND o.created_at>='2026-01-01'
GROUP BY u.id,u.name
ORDER BY orders desc
LIMIT 20;
The clauses are now easy to find, but the output also shows why review matters. The compound LEFT JOIN is split into LEFT and JOIN because JOIN is itself a major clause, and the ON line is not indented at the top level because each line is trimmed. The select list is still one long line, the operators have no added spaces, and count and desc remain lowercase because they are not in the keyword list. If your team wants one column per line, do that part by hand or use a full dialect-aware formatter. The value here is structural clarity, not cosmetic perfection.
The indentation also follows parentheses. A subquery inside FROM shifts its contents right by two spaces, and a closing parenthesis outdents one level. Deeply nested queries can still become tall, but the nesting is visible instead of hidden in a single line.
Quoted literals and comments need review
Single-quoted strings and double-quoted identifiers are protected from keyword uppercasing. That means a value such as 'select all' keeps its lowercase text. However, whitespace is collapsed before that protection, so a literal containing two intentional spaces becomes one. Minify performs the same collapse, and it is even less careful because it does not protect literals at all. Never minify a statement whose string values contain meaningful spacing without checking the result.
Example 2 shows the more dangerous edge. The input is select id, note from audit where note='please review' -- select latest row;. The formatter treats the SELECT inside the comment as a major clause. The comment marker can end up alone on a line, with the words after it moved to a new line. The output may read:
SELECT id, note
FROM audit
WHERE note='please review' --
SELECT latest row;
The double space inside the literal is gone, and the comment text now looks like a live statement. Remove comments before formatting, or inspect every comment containing a keyword. A similar problem appears with identifiers that match the keyword list. A column named order can trigger an ORDER line break unless it is quoted in a form the tool protects. Dialect-specific quoting such as backticks or square brackets is not protected, so check those names after formatting.
What to verify after formatting
| Job | What the tool does | What you must check |
|---|---|---|
| Keyword case | Uppercases a fixed list of common keywords | Dialect keywords not in the list keep their original case |
| Clause breaks | Starts a new line before major clauses | Compound joins can split, and comments or identifiers can trigger breaks |
| Indentation | Adds space by parenthesis depth | Top-level AND and ON lines lose extra indentation during trimming |
| Literals | Protects quoted text from keyword uppercasing | Repeated spaces inside literals are already collapsed |
| Minify | Collapses all whitespace to single spaces | String values, comments and readability |
| Execution | No connection, no syntax validation | Run against a dev database, not production first |
Dialect limits and unusual syntax
The keyword list covers common SELECT, INSERT, UPDATE and DELETE patterns. It does not cover every extension. PostgreSQL's ILIKE, Snowflake's QUALIFY, Oracle's CONNECT BY, SQL Server's TOP and PostgreSQL's RETURNING are not in the list, so they keep whatever case you typed. That is not harmful by itself, but do not read the output as proof that the query is valid for your engine.
More serious breakage comes from word-boundary matching. If an unquoted identifier happens to equal a keyword, the formatter can uppercase it and insert a line break at the wrong place. Backtick-quoted MySQL identifiers and bracket-quoted SQL Server identifiers are not placeholders, so keywords inside them can be rewritten. Review those statements line by line, and prefer a dialect-aware parser for migrations or generated SQL.
Operators, casts, window frames and vendor-specific functions are left as written. The formatter does not add spaces around =, does not expand SELECT *, and does not add a missing semicolon. Use it to expose the clause skeleton, then finish the style by hand if the query is going into a reviewed migration.
A safe formatting workflow
- Keep the original query in version control or a scratch file before formatting.
- Format a copy and compare the output with the source, especially comments and string literals.
- Check quoted identifiers, backticks and bracket names that could contain keywords.
- Run the formatted statement in a development database or wrap it in a transaction with a rollback.
- Use minify only for logs, transport or a single-line config value, never as the reviewed master copy.
- Store the formatted version as the readable source of truth and re-run the formatter after edits.
If the formatted query fails, the cause is often a comment that moved, an identifier that matched a keyword, or a dialect feature the tool does not understand. Compare the first changed line with the original rather than rewriting the whole statement. For queries built from application strings, format the final SQL after parameter substitution in a safe development environment; the tool has no idea which placeholders are bound at runtime.
When the query is part of an API debugging session, the JSON parse error guide covers the other half of the payload. When a query string contains encoded values, the URL encoding guide explains why a parameter may not match what you see in the editor.