SQL Formatting, Explained

After reading this you will know exactly what an SQL formatter changes, what it leaves untouched, and how to pick the dialect and layout that make a query readable without altering a single row it returns.

What an SQL formatter does

An SQL formatter rewrites the text of a query so its structure is visible at a glance. It does not run the query, connect to a database, or change what the query means. It changes whitespace, line breaks and, optionally, the case of keywords.

Take a query written on one line:

select id,name,email from users where active=1 and created_at>'2024-01-01' order by name;

A formatter turns that into:

SELECT id, name, email FROM users WHERE active = 1 AND created_at > '2024-01-01' ORDER BY name; laid out across several lines, one clause per line, with the column list indented under SELECT.

The two versions are byte-for-byte different but semantically identical. The database parses both into the same execution plan. Every character the formatter touches is either whitespace or the letter case of a reserved word. It never rewrites your table names, and it never touches the contents of a string literal.

Format versus minify

The tool runs in two directions. Pretty-printing expands a query for a human to read. Minifying collapses it to a single line for a machine to store or transmit.

The pretty-printed form adds newlines and indentation. A query with 6 clauses might grow from 90 characters on one line to 12 lines of 8 to 40 characters each. The minified form does the reverse: it strips every newline and collapses runs of whitespace to single spaces, so the same query returns to roughly its original 90 characters.

Minifying is not compression in the file-size sense. A 12-line formatted query and its one-line version differ by the whitespace bytes only, usually a few dozen characters. Use minify when you need a query on a single log line or inside a string in your source code, not to save meaningful space.

When to use it, and when not to

Reach for a formatter when a query has grown past the point where you can read it in one pass. A join across 4 tables with 3 subqueries is far easier to review when each JOIN and WHERE starts on its own line. Formatting before you commit also produces smaller, cleaner diffs: a one-line query shows as a single changed line even when you edited one column, while a formatted query shows exactly which clause moved.

Do not format a query you are about to paste into a tool that is whitespace-sensitive in an unusual way. That is rare in SQL itself, because SQL treats runs of whitespace as a single separator. The real risk is elsewhere: if your query lives inside a shell heredoc, a YAML block, or a language string with its own escaping, reformatting can shift indentation that the surrounding format cares about. Format the SQL, then paste it into the container, not the other way around.

A formatter cannot fix a broken query. If the input has a syntax error, most formatters either stop at the error or reflow the text around it without warning you. Treat clean formatting as a readability aid, not a validity check. Run the query against your database to confirm it parses.

How the layout is decided

There is no formula in the statistical sense here, but there is a clear set of rules the formatter applies in order. Understanding them tells you why the output looks the way it does.

The formatter tokenizes the input into keywords, identifiers, literals, operators and punctuation. It then applies three decisions to each token:

Keyword case
Reserved words such as SELECT, FROM and WHERE are normalized to a single case, usually uppercase. Identifiers (your table and column names) keep their original case, because in some dialects case is significant.
Line breaks
Major clause keywords start a new line. A comma-separated list can either stay inline or break so each item sits on its own line, depending on the tool setting.
Indentation
Each nesting level (a subquery, a parenthesized group) adds one indent unit, commonly 2 or 4 spaces. A subquery 3 levels deep with a 2-space unit sits 6 spaces from the left margin.

The dialect setting changes which words count as keywords. QUALIFY is a keyword in BigQuery and Snowflake but not in standard MySQL, so a MySQL formatter treats qualify as an ordinary identifier and does not uppercase it. Choosing the wrong dialect does not corrupt the query, but it can leave a keyword lowercase or fail to break a line where you expected.

Formatting the default sample

Start from a compact query like the one below and run the formatter with the PostgreSQL dialect, uppercase keywords, and a 2-space indent.

Input (1 line, 138 characters):

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 = true group by u.id, u.name having count(o.id) > 3 order by orders desc;

  1. The tokenizer marks select, from, left join, on, where, group by, having and order by as keywords, and uppercases them.
  2. u, orders, users and the rest stay in their original case as identifiers.
  3. Each major clause keyword moves to a new line at the left margin. The column list after SELECT indents 2 spaces.
  4. The result spans 8 lines. The character count barely changes (about 140 including newlines), but the vertical structure now shows all 8 clauses at a glance.

Run it the other way and the 8 lines collapse back to a single line of 138 characters, identical to the input except for normalized spacing around operators.

Formatting adds 3 whitespace characters and 7 line breaks. The content is unchanged; only the shape differs.

Reading the formatted output

Once a query is formatted, you read it top to bottom as a pipeline. Each clause names one operation: FROM and its joins decide which rows exist, WHERE filters them, GROUP BY collapses them, HAVING filters the groups, and ORDER BY sorts the result. Indentation shows dependency. A block indented under another is subordinate to it.

Use the vertical alignment to spot errors. If you expected 4 joins and the formatted output shows only 3 JOIN lines, you dropped one. If a WHERE condition sits at an unexpected indent, you probably have an unbalanced parenthesis, because indentation tracks nesting depth directly. A closing paren that lands one level too far left or right is a strong hint that your grouping is wrong.

With a 2-space indent, a subquery nested 3 levels deep starts at column 6; with a 4-space indent it starts at column 12. Wider indents make deep nesting obvious but push long lines off the screen sooner.

Common mistakes

The most frequent error is expecting the formatter to preserve intentional string content. It does, but people forget that a string literal can contain SQL-looking text. The literal 'SELECT * FROM x' inside your query is data, not code. The formatter leaves it exactly as written, lowercase keywords and all. If you wanted that text uppercased, the formatter will not do it, and that is correct behavior.

The second mistake is formatting comments away. Some settings collapse or move comments. A line comment starting with -- runs to the end of the line, so if a formatter joins two lines it can accidentally comment out code that followed. Check that inline comments still sit where you meant after formatting.

The third is dialect drift. If you format a BigQuery query with a T-SQL profile, backtick-quoted identifiers and QUALIFY may be mishandled. The output stays runnable in most cases, but the casing and line breaks will not match the dialect's conventions.

Related tools

SQL is one of several text formats you handle daily. For structured data, the JSON Formatter & Validator does the same pretty-print and minify job for JSON, and unlike SQL it also validates. When you need to move data between formats, the data converter handles JSON, YAML, TOML, XML and CSV. To compare two versions of a config or result set, the JSON Diff shows a structural difference rather than a line difference.

When a query gets embedded in code, the String Escaper handles the quoting and escaping so your SQL survives inside a language string. If you are matching patterns rather than formatting, the Regex Tester explains a regular expression in plain English as you build it.

Frequently asked questions

Does formatting change what my query returns?

No. Formatting changes only whitespace and keyword case. SQL treats any run of whitespace as a single separator, and keyword matching is case-insensitive in every major dialect, so the parsed query is identical. Your result set does not change.

Will it modify my string literals?

No. Everything between quotes is data. The formatter leaves the bytes inside '...' or "..." exactly as you wrote them, including any lowercase keywords or line breaks stored in the string.

Why does the wrong dialect leave some keywords lowercase?

Each dialect has its own reserved word list. A word that is a keyword in BigQuery, such as QUALIFY, is treated as a plain identifier in MySQL. Under the MySQL profile the formatter has no reason to uppercase it, so it stays as typed. Pick the dialect that matches your database.

Is any of my SQL sent to a server?

No. The formatting runs entirely in your browser using the sql-formatter library. Nothing you paste leaves your device, so it is safe to format queries that contain table names or logic you would not want to upload.

Can it fix a syntax error?

No. A formatter reflows valid tokens. If the input is not valid SQL, the output may look tidy but will still fail when your database parses it. Always run the query to confirm it works.