SQL Prettier: format, beautify and minify SQL in your browser
SQL rarely arrives tidy. It comes out of an application log as a single 900-character line, out of an ORM’s debug output with aliases like t0 and t1, or out of a BI tool’s “view generated SQL” panel with no line breaks at all. Add random casing — Select … FROM … where — and three levels of nested subqueries, and simply reading the query becomes the hard part. This SQL formatter takes that mess, tokenises it, and re-prints it as clean, consistently indented SQL.
How the formatter decides where the lines go
The tool runs a tokenise → print → refine pipeline. First the query is split into tokens: keywords, identifiers, numbers, operators, single-quoted strings, dollar-quoted bodies, and --, # and /* */ comments. Then a clause-aware printer emits those tokens, giving each top-level clause its own line and opening an indent level at every (. Finally the optional refinements run — leading commas, alias alignment, one column per line, print-width wrapping.
The property that matters is that only the whitespace between tokens changes. String literals, dollar-quoted function bodies and comment text are opaque to the printer, so a formatted query returns exactly what the original did. A literal containing -- is not mistaken for a comment, and a comment containing a quote does not swallow the rest of the statement.
Dialects, and why they change the output
Fourteen dialects are supported: Standard SQL, MySQL, MariaDB, PostgreSQL, SQLite, SQL Server (T-SQL), Oracle PL/SQL, BigQuery, Snowflake, Redshift, Db2, Hive, Spark SQL and Trino/Presto. The dialect controls two things that a formatter cannot guess: the reserved-word list and the identifier quoting rules. T-SQL quotes with [square brackets], MySQL with backticks, and PostgreSQL with "double quotes" — each is preserved verbatim and never re-cased. PostgreSQL :: casts and $$ … $$ bodies survive intact, as do BigQuery’s backtick-qualified project.dataset.table names.
If you are not sure which dialect a query came from, the tool scores the syntax it finds — brackets and GETDATE() point at T-SQL, QUALIFY at Snowflake, ROWNUM and NVL() at Oracle — and offers the best guess as a one-click switch.
Team style: casing, commas and the river
Keywords, functions and data types each get their own casing control, so uppercase keywords with lowercase function names is a setting rather than a manual edit. Identifier case is deliberately separate and defaults to Preserve.
Leading commas put the separator at the start of the next line rather than the end of the current one. The payoff is diff noise: adding a column to a trailing-comma SELECT list touches two lines, because the previously-last column gains a comma. With leading commas it touches one. Tabular (or “river”) layout right-aligns clause keywords in a fixed gutter so the query body forms a clean vertical channel — the house style at many analytics teams.
Minify, and check-only diff
Minify runs the pipeline in reverse: the query is normalised first, then collapsed to a single line for embedding in a string literal, a config file or a one-line CLI invocation, with a character-count and percentage readout alongside. Because a -- comment would swallow everything after it on a single line, kept comments are rewritten as /* */ blocks rather than silently breaking the query.
Check-only mode formats the query and shows a unified diff instead of just the result, with added and removed line counts. It reports “already formatted” when nothing would change, which makes it a quick manual pre-commit check that a pull request really is whitespace-only.
Reading the query back
Alongside the formatted output the tool reports what it found: the number of statements, the CTEs by name, joins broken down by type, subqueries, window functions, CASE expressions, set operations, and the maximum parenthesis nesting depth. Those counts come from the token stream, not a regular expression over the raw text, so the word JOIN inside a string literal is never counted. Past a depth of about three, lifting the inner queries into CTEs almost always reads better than nesting them further. A table and column inventory and a CSV export of the metrics round out the analysis.