A SQL formatter takes a SQL string and re-emits it indented and consistently capitalized. The tool above runs the formatter in your browser; nothing leaves your machine.
What gets normalized
| Aspect | Common default |
|---|---|
| Keyword capitalization | UPPERCASE for SQL keywords (SELECT, FROM, WHERE, JOIN) |
| Identifier capitalization | Preserved as written (table and column names) |
| Indentation | Each major clause on its own line, indented |
| Comma placement | After the column (most common) or before (some style guides) |
| Operator alignment | Optional — align = in WHERE clauses |
A typical formatted query:
SELECT
u.id,
u.email,
COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o
ON o.user_id = u.id
WHERE u.created_at > '2024-01-01'
AND u.status = 'active'
GROUP BY u.id, u.email
HAVING COUNT(o.id) > 0
ORDER BY order_count DESC
LIMIT 100;
Each major clause (SELECT, FROM, WHERE, GROUP BY, etc.) starts on its own line. Subordinate parts (column lists, join conditions) are indented under their clause. Subqueries get nested indentation.
What’s stylistic vs syntactic
SQL is whitespace-insensitive almost everywhere. The formatter has freedom on:
- Indentation (2 vs 4 spaces vs tabs).
- Whether to put each column on its own line or pack them.
- Whether to capitalize keywords (UPPER, lower, or Mixed).
- Whether to put
JOINconditions on the same line asJOINor on the next. - Whether commas go before or after the next item.
What’s not stylistic:
- Whitespace inside string literals (
'New York'is one literal; the formatter must not break it). - Whitespace inside identifiers (
"first name"quoted identifiers). - Whitespace inside specific syntax tokens (
!=is one token; can’t be split).
Dialect differences
SQL is famously unstandardized in practice. Each major database has extensions a formatter must recognize or it’ll mangle:
| Dialect | Notable extensions |
|---|---|
| PostgreSQL | RETURNING, WITH RECURSIVE, array operators (@>, <@), JSON operators (->, ->>) |
| MySQL | Backticks for identifiers, LIMIT offset, count, INSERT IGNORE |
| SQL Server | Square brackets for identifiers, TOP N, MERGE syntax |
| Oracle | (+) for outer joins (legacy), CONNECT BY for hierarchical |
| SQLite | Accepts most ANSI plus some non-standard things (no RIGHT JOIN historically) |
| BigQuery | Standard SQL plus STRUCT, ARRAY, UNNEST |
| Snowflake | Standard SQL plus FLATTEN, LATERAL FLATTEN |
A formatter built for one dialect may not handle another’s extensions. Pick a dialect-aware formatter (most modern ones detect via a flag); the tool above defaults to ANSI/standard SQL.
CTEs (WITH clauses)
Common Table Expressions get formatted as their own block:
WITH active_users AS (
SELECT id, email
FROM users
WHERE status = 'active'
),
user_stats AS (
SELECT
user_id,
COUNT(*) AS order_count
FROM orders
GROUP BY user_id
)
SELECT
u.email,
s.order_count
FROM active_users u
LEFT JOIN user_stats s
ON s.user_id = u.id;
Each CTE is its own indented block. The trailing , separates CTEs; the final SELECT is the main query.
Inline vs block formatting
Two valid formatted styles:
-- Block (most common):
SELECT
id,
email,
created_at
FROM users
WHERE status = 'active';
-- Inline (compact):
SELECT id, email, created_at
FROM users
WHERE status = 'active';
Block is more readable for long column lists or complex queries. Inline is faster to type and read for short queries. Most formatters offer a “max columns inline” threshold.
What the formatter doesn’t do
- Doesn’t optimize. A formatter doesn’t rewrite
SELECT * FROM users WHERE id IN (1)toSELECT * FROM users WHERE id = 1. That’s optimization, not formatting. - Doesn’t validate semantically. It checks the parse, not whether the columns exist or the syntax is correct for the target database.
- Doesn’t comment. No “this query is slow” hints.
- Doesn’t reorder. Column lists are preserved in input order.
Comments
-- Single-line comment
/* Multi-line
comment */
Both forms are universal. Some dialects also accept # (MySQL) for single-line. Formatters preserve comments and place them on their own lines (block) or end-of-line (inline) depending on their original position.
When formatting is wrong
- Production code with strict structure requirements. Some teams have specific SQL style guides (column-name alignment, specific casing rules, comma placement). A generic formatter may not match. Use a dialect-and-style-aware formatter or hand-format.
- Tiny one-line queries.
SELECT 1doesn’t need formatting. Don’t. - Embedded SQL strings. SQL inside JavaScript template literals or Python f-strings — the formatter sees only the string content, not the surrounding code.
Common pitfalls
- Formatting dynamic SQL. SQL strings built by concatenation often have placeholders or template syntax (
$1,?,:name). The formatter may not recognize them. - Backticks vs double-quotes vs square brackets. MySQL backticks vs ANSI double-quotes vs SQL Server square brackets — pick the dialect mode that matches your database.
ASaliases.SELECT user_id user_idis valid (the second is the alias). The formatter usually addsASfor readability:SELECT user_id AS user_id. Sometimes this is what you want; sometimes it’s pointless noise.- Stripping intentional whitespace in string literals. A naïve formatter might collapse spaces in
'New York'to'New York'. A correct one preserves string contents. - Re-formatting. Idempotent for proper formatters. If the second pass differs from the first, the formatter has a bug.
For other format tools, see JSON formatter, HTML formatter, CSS formatter, XML formatter.