induwara.lk
induwara.lkDeveloper · Browser-only

SQL Formatter — beautify, minify, and pretty-print SQL

Paste compressed SQL to pretty-print it for MySQL, PostgreSQL, SQLite, SQL Server, Oracle, BigQuery, or Snowflake. Choose keyword case, indent style, and tab width. The minifier strips comments and collapses whitespace without breaking strings. Nothing is uploaded.

By Induwara AshinsanaUpdated May 11, 2026
SQL Formatter
Runs in your browser
Dialect
Keyword case
Indent style
Tab width

245 characters, 1 lines.

Idempotent — formatting the output again produces the same text.

Status
Formatted
Fixed-point reached
Statements
1
From 1 input lines
Output size
279
+13.9% vs input
Keywords
8
SELECT, FROM, JOIN +5 more

How it works

The formatting engine on this page is sql-formatter (Apache-2.0), a dialect-aware reformatter used inside Prisma Studio, dbt and similar tools. It ships hand-written tokenizers for each dialect, so the parser knows that backticks open an identifier in MySQL but a string literal in BigQuery, that $$body$$ is a PostgreSQL multi-line string, and that [name] is a Transact-SQL identifier. After tokenising, it emits clauses onto fresh lines with consistent indentation and applies the chosen keyword case.

The minify button uses a small, dialect-agnostic walker written for this site. It steps through the input one character at a time and tracks which lexical state it is in: code, single-quoted string, double-quoted identifier, MySQL backtick, T-SQL bracket, PostgreSQL dollar-quoted block, line comment, or block comment. Only when the walker is in code does it collapse whitespace and drop comments — so a -- inside a string literal, or a ; inside a dollar-quoted body, survives untouched. The same walker powers the statements counter, so it never miscounts a semicolon that happens to sit inside a string.

Every successful format also runs an idempotency check: the formatter is invoked a second time on its own output, and the two outputs are compared byte-for-byte. A properly designed pretty-printer is supposed to reach a fixed point — re-running it should not keep changing the text. The status tile confirms that property held for your query. If it ever fails, the page surfaces a warning so you can report a real parser bug rather than chasing a phantom diff.

Output stats include the number of statements (driven by the string-aware counter, not a naive split on ;), the output byte count and percentage delta versus the input, and a list of top-level SQL keywords that appeared. The keyword detector runs against the minified form of the input so words inside string literals and comments do not get counted as keywords.

One caveat: this version does not handle PostgreSQL’s nested block comments. Those are rare in human-written queries — the ANSI standard does not allow them at all — but if your input contains them, switch to plain line comments first or pre-strip them in your editor. Everything else in the lexical specification of the supported dialects is honoured.

Worked examples

Beautify a compressed SELECT

Input

SELECT id,name FROM users WHERE active=1 ORDER BY id;

Output

SELECT
  id,
  name
FROM
  users
WHERE
  active = 1
ORDER BY
  id;

MySQL dialect, UPPER keyword case, 2-space indent. Each clause gets its own line; operands indent below.

Pretty-print a JOIN with aggregates

Input

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

Output

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
GROUP BY
  u.id,
  u.name
HAVING
  count(o.id) > 0
ORDER BY
  orders DESC
LIMIT
  10;

JOIN, GROUP BY, HAVING, ORDER BY, LIMIT — all wrapped, with the JOIN clauses indented under FROM.

Minify safely, preserving strings

Input

UPDATE products
  SET notes = 'discount -- end of season'  -- editorial note
WHERE id = 42;

Output

UPDATE products SET notes = 'discount -- end of season' WHERE id = 42;

The literal `-- end of season` is INSIDE the string and must not be treated as a line comment — the string-aware walker keeps it intact. The trailing editorial line comment is stripped.

Frequently asked questions

Sources & references

Related tools

Rate this tool
Be the first to rate

Comments & feedback

Spotted a bug or want an improvement? Tell us — our team reviews every comment, and good ideas get built. Comments are public and anonymous.

Found a bug, edge case, or want to suggest an improvement?

Email me at [email protected] — most fixes ship within 24 hours.