SQL Formatter & Beautifier
Paste a query to indent it, uppercase its keywords, or minify it to one line. Choose PostgreSQL, MySQL or SQLite where the engines read the same text differently. String literals are never rewritten, and nothing leaves your browser.
More from SQLFormat
Guides
Frequently Asked Questions
Is my query sent to a server?
No. Formatting is done in your browser, so queries containing table names, schema details, or literal data are never uploaded.
Which SQL dialects does the formatter handle?
Layout is one engine-agnostic pass: unambiguous syntax survives intact in both format and minify — JSONB path operators (#>, #>>, #-), :: casts, backtick identifiers, DISTINCT ON, ILIKE and dollar-quoting all come through character-for-character. The dialect select exists for the two spellings that mean opposite things in two engines and cannot be told apart from the text: a bare # (MySQL line comment vs PostgreSQL integer XOR) and a backslash inside single quotes (MySQL escape vs literal character in PostgreSQL and SQLite). Auto keeps the MySQL readings; pick your engine if your query uses either spelling.
Can it make unreadable legacy SQL readable?
Yes. Paste a single-line query and the formatter breaks it on clause boundaries and indents nested subqueries, which is usually enough to review. It never rewrites identifiers or logic.
🧭 Pro Tips & Gotchas
What the formatter actually does
- It is keyword-anchored, not a SQL parser: recognised clauses (
SELECT,FROM,WHERE,JOIN,GROUP BY,ORDER BY,HAVING,AND/OR) get their own line and indent level. - Uppercase toggle rewrites keywords by word-boundary matching, so
order_idis left alone while a bareorderis treated as theORDERkeyword. - Indent size is applied per nesting level, which is what makes subqueries readable — and what makes deeply nested CTEs drift off-screen.
Gotchas
- Strings and quoted identifiers are protected. A literal containing
from('select * from users') stays on one line, and so do commas, semicolons, parens and quotes inside it — the tokenizer reads the whole literal as one token before any layout happens. Tested against 8 literal shapes; none were split. - What is not protected is your whitespace inside a literal: a literal containing a newline keeps it, so a multi-line string still multi-line-breaks the output visually even though nothing was lost.
UPPERCASErewrites any word that happens to be a keyword, including one you used as an identifier:SELECT order FROM orders AS ordercomes back asSELECT ORDER ... AS ORDER. Quote it ("order", `order`) to protect it, or leave the toggle off — with the toggle off, your original casing is reproduced exactly.- A window definition gets reflowed as if it were query structure: inside
OVER (...),ORDER BYbreaks onto its own line at the outer indent and the closing paren lands at column 0. Nothing is lost, but the window clause no longer reads as one unit. CheckOVER (...)after formatting. - Dialect extensions get layout, not understanding.
RETURNINGbreaks onto its own line and aLATERALsubquery indents, because both are matched as keywords — not because the formatter knows PostgreSQL.QUALIFYstays glued to the line it is on, and BigQuery'sSELECT * EXCEPT (...)is read as a set-operationEXCEPT, so it breaks where a BigQuery reader would not expect. Nothing errors; that is the trade. - Minify deletes comments.
-- note,# noteand/ note /are all removed, not compressed. Anything an audit trail depends on is gone after a minify pass, in every engine's comment style. - The dialect select changes exactly two readings, not the layout. The formatting pass is identical in every mode; the select decides how a bare
#is read (MySQL line comment vs PostgreSQL integer XOR — Auto and MySQL trim everything after it, PostgreSQL keepsflags # 4as a predicate) and whether a backslash inside single quotes escapes the next character (MySQL) or stays a literal character (PostgreSQL withstandard_conforming_strings=on, and SQLite — where'C:\'genuinely meansC:\). Past a string ending in a backslash, the wrong mode can fuse two literals or split one across lines — so if your SQL contains either spelling, pick your engine. - Do not minify nested block comments (
/ a / b / c /). No engine supports nesting, the tokenizer stops at the first/, and the remainder gets reassembled as operators. The same applies to an unterminated/, which swallows the rest of the statement. - Comments survive positionally, not semantically — a trailing
-- notecan end up leading the next clause after reflow. - Because there is no parser, the formatter cannot validate. It will happily prettify syntactically broken SQL and make it look correct, which is worse than ugly broken SQL.
- For anything machine-generated, prefer a real formatter (
sqlglot,sqlfmt,pg-formatter) and keep this for interactive scratch work.