Skip to content

SQL Formatter

Format SQL queries with proper indentation, keywords, and dialect-aware syntax.

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

AspectCommon default
Keyword capitalizationUPPERCASE for SQL keywords (SELECT, FROM, WHERE, JOIN)
Identifier capitalizationPreserved as written (table and column names)
IndentationEach major clause on its own line, indented
Comma placementAfter the column (most common) or before (some style guides)
Operator alignmentOptional — 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 JOIN conditions on the same line as JOIN or 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:

DialectNotable extensions
PostgreSQLRETURNING, WITH RECURSIVE, array operators (@>, <@), JSON operators (->, ->>)
MySQLBackticks for identifiers, LIMIT offset, count, INSERT IGNORE
SQL ServerSquare brackets for identifiers, TOP N, MERGE syntax
Oracle(+) for outer joins (legacy), CONNECT BY for hierarchical
SQLiteAccepts most ANSI plus some non-standard things (no RIGHT JOIN historically)
BigQueryStandard SQL plus STRUCT, ARRAY, UNNEST
SnowflakeStandard 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) to SELECT * 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 1 doesn’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.
  • AS aliases. SELECT user_id user_id is valid (the second is the alias). The formatter usually adds AS for 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.