SQL Formatter & Beautifier

Turn unreadable one-line SQL into clean, indented, reviewable code.

Input SQL
Formatted

    

Why formatting SQL matters more than formatting most code

SQL is unusual: it is read far more often than it is written, and its readers are frequently not the author. A query written once during a feature launch gets read during an incident six months later, by someone with no context, at speed. Unformatted SQL makes that reading actively error-prone.

There is also a concrete mechanical benefit. Version control diffs are line-based. In a one-line query, changing one predicate rewrites the entire line, so the diff shows everything as changed and reviewers cannot see what you actually did. In formatted SQL, one clause per line means one changed line.

A before-and-after

-- Before: one line, 200 characters, unreadable
select u.id,u.email,count(o.id) as order_count,sum(o.total_cents)/100 as revenue from users u left join orders o on o.user_id=u.id and o.status<>'cancelled' where u.created_at>='2026-01-01' and u.deleted_at is null group by u.id,u.email having count(o.id)>3 order by revenue desc limit 50;
-- After: one clause per line, joins visible, intent obvious
SELECT
  u.id,
  u.email,
  COUNT(o.id) AS order_count,
  SUM(o.total_cents) / 100 AS revenue
FROM users u
LEFT JOIN orders o
  ON o.user_id = u.id
  AND o.status <> 'cancelled'
WHERE u.created_at >= '2026-01-01'
  AND u.deleted_at IS NULL
GROUP BY u.id, u.email
HAVING COUNT(o.id) > 3
ORDER BY revenue DESC
LIMIT 50;

The second version takes more vertical space and is unambiguously better. You can see the join condition, you can see which predicate belongs to the join and which to the filter, and you can see that HAVING applies after GROUP BY.

Conventions worth adopting as a team

Uppercase keywords, lowercase identifiers

Write SELECT, FROM, WHERE in uppercase and table/column names in lowercase. This makes the structure of the query legible at a glance and survives syntax highlighting being unavailable — in a code review comment, a Slack message, or a terminal.

One major clause per line

Put SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY and LIMIT each on its own line. Indent their contents one level. This is the single highest-value rule.

Put join conditions on their own lines

ON clauses with multiple conditions should be split across lines. The most common SQL bug in practice is a join predicate accidentally placed in WHERE, which silently converts an outer join into an inner join. Making the distinction visible prevents it:

-- Correct: filter belongs to the join, unmatched rows survive
LEFT JOIN orders o
  ON o.user_id = u.id
  AND o.status = 'paid'

-- Bug: this silently turns the LEFT JOIN into an INNER JOIN
LEFT JOIN orders o ON o.user_id = u.id
WHERE o.status = 'paid'

Alias every table, qualify every column

In multi-table queries, prefix every column with its alias. Six months from now, nobody knows whether id means u.id or o.id — and if a column is later added to both tables, the query breaks with an ambiguity error.

Trailing commas, not leading

Use trailing commas at the end of each selected column. SQL, unlike JavaScript, generally does not tolerate a trailing comma before FROM — so placing commas at line end keeps the last column clean and makes diffs additive.

Formatting does not fix performance

A beautifully formatted query can still be catastrophically slow. Formatting improves readability; it says nothing about execution. When a query is slow, the tools that matter are EXPLAIN and EXPLAIN ANALYZE, which show you the actual plan.

The highest-impact structural checks:

  • Is there an index supporting each WHERE predicate and each JOIN key?
  • Are you selecting columns you do not need? SELECT * prevents index-only scans and breaks when the schema changes.
  • Is a function wrapping an indexed column — WHERE DATE(created_at) = … — which makes the index unusable? Rewrite as a range comparison.
  • Is a LIKE '%term' leading-wildcard scan running against a large table? Those cannot use a standard B-tree index.

A note on this formatter

Dialects differ, and a formatter tokenises rather than fully parses, so deeply nested CTEs, window functions and vendor-specific syntax may occasionally indent in a way you would not choose by hand. Always read the output before committing it. The formatter is a starting point, not an oracle — and for anything destined for production, the query plan matters far more than the indentation.

Frequently asked questions

No. Whitespace is insignificant to the SQL parser, so formatting changes readability only. Execution depends on the query plan, which you inspect with EXPLAIN.

No. All formatting happens in JavaScript in your browser. Nothing is logged or transmitted, so it is safe to paste queries containing real table and column names.

The keyword set covers standard SQL plus common PostgreSQL, MySQL and SQLite constructs: CTEs, window functions, joins, INSERT … ON CONFLICT, RETURNING. Highly vendor-specific syntax may format imperfectly — always review the result.

It is the dominant convention and makes structure readable without syntax highlighting. The more important thing is consistency within a codebase. Uncheck the box if your team prefers lowercase.

A predicate on the right-hand table placed in WHERE rather than in ON filters out the NULL-extended rows, converting the outer join into an inner one. Move the condition into the ON clause.