Format a SQL query into something readable, or collapse it back to one line. Pick one of twelve dialects, because a backtick quotes an identifier in MySQL and is a syntax error in PostgreSQL.
select u.id,u.name,count(o.id) as orders,sum(o.total) as spent from users u left join orders o on o.user_id=u.id where u.created_at>='2026-01-01' and u.active=true group by u.id,u.name having count(o.id)>2 order by spent desc limit 20; SELECT
u.id,
u.name,
count(o.id) AS orders,
sum(o.total) AS spent
FROM
users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE
u.created_at >= '2026-01-01'
AND u.active = TRUE
GROUP BY
u.id,
u.name
HAVING
count(o.id) > 2
ORDER BY
spent DESC
LIMIT
20; Pick the dialect your database speaks. Dialects disagree about more than keywords. MySQL quotes identifiers with backticks, PostgreSQL and standard SQL use double quotes, and SQL Server uses square brackets. With the wrong dialect, the formatter can misread a quoted identifier as a string, or a string as an identifier, and the result may not run.
The rest works the same in every dialect: the tokens stay as they are and only the whitespace moves. No clause is reordered, no join is rewritten and nothing is added. Uppercase keywords against lowercase identifiers is the usual convention, because the SELECT, FROM and WHERE lines then show the shape of a long query before you read it.
?, $1, :name and @name pass through untouched, so a parameterized query stays parameterized. Pasting values into SQL is how injection happens, so bind them instead.
Format keeps both -- line comments and /* block */ comments where they were. Minify drops -- comments, because on a single line they would comment out everything after them.
The formatter is built for queries. PL/pgSQL bodies, T-SQL control flow and stored procedures still come out valid, but sometimes oddly indented.
The Minify button collapses the query to one line for a string literal or a log line. It also collapses runs of spaces inside string literals, so keep the formatted version if a value depends on them.
# npm i -D sql-formatter
npx sql-formatter -l postgresql --fix migrations/*.sql
# sqlfluff both lints and formats, and understands more dialects
pip install sqlfluff
sqlfluff format --dialect postgres queries/
sqlfluff lint --dialect postgres queries/
# .pre-commit-config.yaml
# - repo: https://github.com/sqlfluff/sqlfluff
# rev: 3.2.5
# hooks:
# - id: sqlfluff-format
# args: [--dialect, postgres] // npm i sql-formatter
const { format } = require("sql-formatter");
console.log(format(query, {
language: "postgresql",
keywordCase: "upper",
tabWidth: 2,
}));
// Formatting is cosmetic. This is the part that matters:
// never build SQL by concatenating values.
await client.query(
"SELECT * FROM users WHERE email = $1 AND active = $2",
[email, true],
); # pip install sqlparse
import sqlparse
print(sqlparse.format(
query,
reindent=True,
keyword_case="upper",
indent_width=2,
))
# Parameterised, always
cur.execute(
"SELECT * FROM users WHERE email = %s AND active = %s",
(email, True),
) Write keywords in uppercase and identifiers in lowercase. The SELECT, FROM, WHERE and JOIN lines then form a skeleton you can follow without reading every token. The habit comes from terminals without syntax highlighting, and it still helps in a log file, a migration diff or a code review comment, none of which are highlighted either.
This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.
PostgreSQL, MySQL, MariaDB, SQLite, SQL Server (T-SQL), BigQuery, Snowflake, Redshift, Db2, Hive, Spark and standard SQL. Pick the one your database uses, because dialects disagree about quoting, and the wrong choice can mangle an identifier.
No. Format reprints the same tokens with different whitespace. It does not rewrite joins, reorder clauses or add anything, and string literals stay exactly as they are.
Yes, and it can also lowercase them or leave them as written. Uppercase keywords against lowercase identifiers is the most common convention, because it makes the shape of a long query readable at a glance.
Yes. ?, $1, :name and @name all survive formatting, so a parameterized query stays parameterized. Never build a query by pasting values into it; that is where most SQL injection comes from.
The formatter is built for queries. Procedural blocks, PL/pgSQL bodies and vendor-specific control flow are only partly understood and can end up oddly indented. The SQL still runs; it only looks worse than it should.
To load data rather than query it, CSV to SQL INSERT turns a spreadsheet export into statements. Results usually come back as JSON, which the JSON formatter and JSON table viewer handle.