About SQL Formatter
Formatting SQL makes a long query readable, which matters more than it sounds: most SQL that needs formatting is SQL somebody is trying to understand under pressure, usually because it is slow or returning the wrong rows.
The conventions that help most are consistent keyword casing, one column or condition per line, and indentation that makes join and subquery nesting visible. Uppercase keywords against lowercase identifiers is the most widespread style because it lets you see the query's shape without reading it - and consistency matters more than which convention you pick.
Formatting is purely cosmetic to the database. The optimiser parses SQL into a tree and whitespace is discarded, so reformatting cannot change a query plan. The one thing to be careful of is that a formatter is not a parser for every dialect: PostgreSQL's dollar-quoted function bodies, T-SQL's square-bracketed identifiers, MySQL's backticks and vendor-specific hint syntax all confuse some formatters, which may reflow something they should have left alone.
The related caution is that reformatting a query changes its text, and some systems key on exactly that. Query plan caches, prepared statement identifiers, and monitoring tools that group by query text will treat a reformatted query as a new one. That is harmless but can briefly distort a dashboard.
Formatting runs in your browser, so a query containing real table and column names is not uploaded.
How to use the SQL Formatter
- Paste the SQL - a single line from a log, or an already-formatted query you want restyled.
- Format, and read the structure: the join order and any nesting should now be visible.
- Check that dialect-specific syntax survived - dollar quoting, bracketed identifiers, hints.
- Copy the result. If you are pasting into a repository, match whatever style is already there.
SQL Formatter in code
The same operation this tool performs, in the languages you are most likely to need it.
-- Before: one line out of a slow query log
select u.id,u.email,count(o.id) as orders from users u left join orders o on o.user_id=u.id where u.created_at>='2026-01-01' and u.status='active' group by u.id,u.email having count(o.id)>5 order by orders desc limit 100;
-- After
SELECT
u.id,
u.email,
COUNT(o.id) AS orders
FROM users u
LEFT JOIN orders o
ON o.user_id = u.id
WHERE u.created_at >= '2026-01-01'
AND u.status = 'active'
GROUP BY
u.id,
u.email
HAVING COUNT(o.id) > 5
ORDER BY orders DESC
LIMIT 100;
# sqlfluff - formatter and linter, dialect-aware
pip install sqlfluff
sqlfluff format --dialect postgres query.sql
sqlfluff lint --dialect postgres query.sql
# In CI, fail on unformatted SQL
sqlfluff lint --dialect postgres models/ || exit 1
# pg_format for PostgreSQL specifically
pg_format -s 4 query.sql
# Node
npx sql-formatter --language postgresql query.sql
-- Formatting does not change the plan. This does:
EXPLAIN (ANALYZE, BUFFERS) SELECT ...; -- PostgreSQL
EXPLAIN ANALYZE SELECT ...; -- MySQL 8+
-- Read the plan for: sequential scans on large tables, a row
-- estimate far from the actual count (stale statistics), and
-- nested loops over many rows.
-- The usual real fixes:
CREATE INDEX CONCURRENTLY idx_orders_user_id ON orders (user_id);
ANALYZE orders; -- refresh statistics
-- A function on an indexed column prevents index use:
WHERE DATE(created_at) = '2026-01-01' -- no index
WHERE created_at >= '2026-01-01'
AND created_at < '2026-01-02' -- index used
When you need this
- Making a one-line query from a slow query log readable.
- Restyling SQL to match a project's conventions before committing it.
- Formatting generated SQL from an ORM to see what it actually does.
- Laying out a long query so a join or subquery mistake becomes visible.
Common problems and what causes them
- Expecting formatting to affect performance
- It cannot. The parser discards whitespace, so the plan is identical. If a query is slow, read EXPLAIN ANALYZE - the answer is almost always a missing index, stale statistics, or a function applied to an indexed column.
- Dialect-specific syntax mangled
- PostgreSQL dollar quoting ($$ ... $$), T-SQL [bracketed identifiers], MySQL `backticks` and optimiser hints all confuse formatters that do not know the dialect. Always tell the formatter which dialect it is reading.
- String literals and comments reflowed
- A poor formatter can alter whitespace inside a string literal, which changes the value, or move a line comment so it comments out the wrong code. Check anything with embedded text carefully.
- Reformatting invalidating plan caches
- Query text is the cache key in several systems, so a reformatted query is a new query - a new plan, a new prepared statement, and a new row in monitoring tools that group by text. Harmless, but it can look alarming on a dashboard.
- Formatting instead of parameterising
- A long query built by string concatenation is a SQL injection risk regardless of how neatly it is laid out. Formatting makes it readable; parameter binding makes it safe.
FAQ
- Does formatting SQL change how it performs?
- No. Whitespace is discarded during parsing, so the execution plan is unchanged. Use EXPLAIN ANALYZE to understand performance - the usual culprits are missing indexes, stale statistics, and functions wrapped around indexed columns.
- Should SQL keywords be uppercase?
- It is the most common convention and it makes a query's shape readable at a glance, but it is purely stylistic. Consistency within a codebase matters far more than the choice, and a formatter in CI is what actually enforces it.
- Why did the formatter break my query?
- Most likely dialect-specific syntax it does not recognise - dollar-quoted function bodies, bracketed or backticked identifiers, or optimiser hints. Specify the dialect, and check anything containing string literals or comments.
- Can I enforce SQL formatting automatically?
- Yes - sqlfluff lints and formats with dialect awareness and runs well in CI or a pre-commit hook. That removes formatting from code review entirely, which is generally where you want it.