tidysql
Format SQL in seconds. No login. No install. Just clean code.
The input: one line of minified PostgreSQL
select id,name,created_at from orders where status='pending' order by created_at desc limit 25
That's the whole query. Three clauses jammed onto one line, lowercase keywords, no spaces after the commas in the column list, a string literal sitting flush against the equals sign. It's the shape SQL takes when it falls out of an ORM debug log or shows up in a slow-query report from RDS Performance Insights.
Paste that string into the formatter, leave the dialect on PostgreSQL, keyword case on UPPER, indent on 2 spaces, and click Format. What comes back is eight lines.
What the formatter does to it, step by step
Tidysql hands the input to sql-formatter v15.4.0, which parses the string into an AST and re-prints it according to the dialect, case, and indent settings on the options bar. The library is MIT licensed and runs synchronously inside the browser tab. Nothing leaves the page. CodeBeautify.com and Aiven.io ship the same library under the hood; the difference is what the surrounding tool does with the parsed AST.
For this specific input, here's the rebuild in order:
- Uppercases every reserved word it recognizes (
selectbecomesSELECT,frombecomesFROM, and so on throughWHERE,ORDER BY,DESC,LIMIT). - Splits the SELECT list onto one column per line, indented two spaces. Three columns means three new lines.
- Puts each top-level clause (
FROM,WHERE,ORDER BY,LIMIT) at column zero on its own line. - Adds a single space on each side of the
=operator sostatus='pending'becomesstatus = 'pending'. - Leaves the string literal
'pending'alone. Single quotes are the standard PostgreSQL string delimiter, and the parser doesn't touch the contents of literals.
The output:
SELECT
id,
name,
created_at
FROM
orders
WHERE
status = 'pending'
ORDER BY
created_at DESC
LIMIT
25One thing to flag: the formatter doesn't validate. If you misspell WERE, the engine will still reject the query at runtime; tidysql will pretty-print the typo without comment, because the parser is permissive enough to keep going on tokens it cannot classify. We tested this against malformed input deliberately during the build and chose to keep the lenient behavior, with a yellow warning banner for the genuinely unparseable cases, instead of refusing to format anything the parser flinched at. A strict mode that rejects on the first unknown token would make the tool useless for the most common input we see, which is half-pasted query fragments out of a debugger.
Reading the diff view: what the green lines mean
Toggle the diff view on (it's on by default in the diff bar at the bottom of the editor) and the output panel will mark every line the formatter added with a green left-edge bar. For the example above, the diff bar at the bottom of the screen reads:
+7 lines added · -0 lines removed · 8 lines total
That math is correct. The original input was one line. The output is eight. Eight minus one is seven new lines, all of them additions; nothing got deleted, because formatting on a single-line input is a pure expansion. The diff bar uses the diff npm package's diffLines algorithm, which treats the input and output as ordered line sets and reports added and removed counts separately rather than collapsing them into a "lines changed" number.
The diff is most useful in the other direction, when you suspect the formatter changed something it shouldn't have. If you ever see a non-zero removed count on a Format pass (rather than a Minify pass), that's the signal to look closely. Comments inside string literals can sometimes confuse a parser into eating a token. We haven't reproduced this failure mode on sql-formatter v15 across the dialects tidysql supports, but the diff bar is where it would surface if it ever did.
Dialect switching mid-example: BigQuery vs. PostgreSQL quoting
Switch the dialect dropdown from PostgreSQL to BigQuery without changing anything else, and the same input reformats with one quiet difference: identifiers stay unquoted in both, because none of id, name, created_at, or orders are reserved words in either dialect. If the table had been named order (singular, which is reserved) the BigQuery output would wrap it in backticks, like `order`, while PostgreSQL would wrap it in double quotes, like "order". T-SQL would use square brackets: [order]. Snowflake would use double quotes like PostgreSQL. The formatter applies the engine's quoting rules from the AST level; it doesn't run a regex pass over the output.
That's why the dialect picker matters even on queries that look generic. Most three-line SELECTs format identically across all 14 supported dialects. The differences only show up around reserved-word identifiers, type casts (::int is PostgreSQL-only and breaks under MySQL), and comment styles (# works in MySQL but is a syntax error in PostgreSQL). The formatter won't fail on those, but it won't rewrite them either; the warning banner appears when the parser cannot place a token at all, not when a token is legal in some other dialect.
If you change the dialect after a successful format, the output panel auto-reformats with the new rules and the diff bar recomputes against the same original input. You can flip between PostgreSQL and BigQuery on one query as many times as you like without re-pasting.
Frequently Asked Questions
How do I format SQL online for free?
What is the best free SQL formatter without ads?
How do I format a PostgreSQL query?
How do I minify SQL into a single line?
Can I see what changed when I format my SQL?
Does Tidysql support MySQL, BigQuery, and Snowflake?
Is my SQL sent to a server when I format it?
Privacy
Your SQL stays in your browser. We don't send it anywhere, log it, or store it. See the privacy policy for the full details.
Built by Infinite Orchard. Powered by sql-formatter v15 (MIT). Questions? Use the Contact Us link in the footer.