Developer Tools

Free SQL Formatter & Beautifier Online

Format, indent and beautify SQL queries. Supports SELECT, INSERT, UPDATE, CREATE and more.

SQL Formatting: Best Practices and Style Guide

SQL is one of the oldest and most widely used languages in computing, yet it has no universally enforced style standard. Different teams write SQL in wildly different styles — uppercase keywords, lowercase keywords, all on one line, spread across dozens of lines, keywords left-aligned, keywords right-aligned. A SQL formatter enforces consistency so that code reviews focus on logic rather than style, and so that queries are readable to every member of the team.

Why SQL Formatting Matters

Unformatted or inconsistently formatted SQL creates real problems:

  • Review overhead: A code reviewer who has to mentally parse a 200-character single-line query is spending cognitive effort on formatting rather than correctness.
  • Debugging difficulty: A properly indented WHERE clause with one condition per line makes it immediately obvious which conditions are combined with AND and which with OR. A single-line query with mixed AND/OR is a source of bugs.
  • Operator precedence: SQL evaluates AND before OR. A query like WHERE a = 1 OR b = 2 AND c = 3 is parsed as WHERE a = 1 OR (b = 2 AND c = 3) — which may not be what was intended. Formatting with explicit parentheses and one condition per line makes the intent clear.
  • Version control diffs: A properly formatted query that changes one condition produces a one-line diff. An unformatted query produces a meaningless full-query diff even for a one-word change.

Keyword Casing Conventions

The most debated style question in SQL is keyword casing. Three schools of thought:

ALL CAPS keywords (most common):

SELECT u.id, u.name, o.total
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.active = TRUE
ORDER BY o.total DESC;

The argument for uppercase keywords: they visually separate language constructs from user-defined identifiers (table names, column names, aliases). When scanning a query, your eye immediately finds SELECT, FROM, and WHERE as structural landmarks. This is the convention used by most database documentation and textbooks.

lowercase keywords (growing trend):

select u.id, u.name, o.total
from users u
join orders o on u.id = o.user_id
where u.active = true
order by o.total desc;

The argument for lowercase: SQL keywords are identifiable by their position in the statement, not by their case. Lowercase is faster to type and looks more natural alongside lowercase table/column names in modern style guides (like the GitLab SQL Style Guide). This is increasingly common in teams with strong Python/Ruby influence.

Preserve original casing: Useful when reformatting queries that mix cases intentionally (for example, in stored procedures where the original author's style should be preserved).

Pick one convention and enforce it with your formatter — the most important thing is consistency within a codebase.

Indentation and Alignment Strategies

Two main approaches to SQL indentation:

Right-aligned keywords (railway style):

  SELECT u.id,
         u.name,
         o.total
    FROM users u
    JOIN orders o ON u.id = o.user_id
   WHERE u.active = TRUE
ORDER BY o.total DESC;

This style right-aligns keywords so they form a vertical column. The data (column names, table names, conditions) all start at the same horizontal position. Advocated by Joe Celko's SQL Style Guide and used by many DBAs. Very readable for individual queries; harder to implement consistently in code generation.

Left-aligned keywords (more common in code):

SELECT
  u.id,
  u.name,
  o.total
FROM users u
JOIN orders o
  ON u.id = o.user_id
WHERE
  u.active = TRUE
ORDER BY o.total DESC;

This style starts keywords at the left margin and indents the content. It's easier to implement in formatters and ORMs, and is the approach used by most automated formatters. The formatter in this tool uses left-aligned keywords.

SELECT List Formatting

For queries with many columns, put each selected expression on its own line:

SELECT
  u.id,
  u.first_name,
  u.last_name,
  u.email,
  u.created_at,
  COUNT(o.id) AS order_count,
  SUM(o.total) AS lifetime_value
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.first_name, u.last_name, u.email, u.created_at;

Avoid SELECT * in production queries — it retrieves all columns including ones you don't need, increases network transfer, defeats covering indexes, and breaks when columns are added or reordered. Always name the columns you need.

WHERE Clause Formatting

The WHERE clause is where bugs most commonly hide. Format it with one condition per line, making operator precedence explicit:

WHERE
  u.active = TRUE
  AND u.role IN ('admin', 'editor')
  AND (
    u.last_login > '2024-01-01'
    OR u.subscription_tier = 'premium'
  )
  AND u.deleted_at IS NULL;

Notice the explicit parentheses around the OR group. Without them, SQL evaluates AND before OR, and this query's semantics would change. Adding parentheses makes the intent unambiguous, regardless of whether they are strictly necessary.

JOIN Formatting

Format each JOIN on its own line, with the ON condition on the next line:

FROM users u
JOIN orders o
  ON u.id = o.user_id
LEFT JOIN order_items i
  ON o.id = i.order_id
  AND i.deleted_at IS NULL
LEFT JOIN products p
  ON i.product_id = p.id;

Always specify the JOIN type explicitly. Use INNER JOIN (or JOIN for brevity) when you want only matched rows. Use LEFT JOIN when you want all rows from the left table even if there is no match on the right. Never use implicit cross joins (comma-separated table names in FROM) — they produce cartesian products and are easy to misread.

Subqueries and CTEs

Common Table Expressions (CTEs) with WITH dramatically improve readability compared to deeply nested subqueries:

-- Hard to read: nested subquery
SELECT *
FROM (
  SELECT u.id, COUNT(o.id) AS cnt
  FROM users u
  LEFT JOIN orders o ON u.id = o.user_id
  GROUP BY u.id
) sub
WHERE sub.cnt > 5;

-- Much better: CTE
WITH user_order_counts AS (
  SELECT
    u.id,
    COUNT(o.id) AS cnt
  FROM users u
  LEFT JOIN orders o ON u.id = o.user_id
  GROUP BY u.id
)
SELECT *
FROM user_order_counts
WHERE cnt > 5;

CTEs are named, appear before the main query, and can reference each other. They make complex queries readable like prose — each CTE is a named step in the data transformation pipeline. Most modern databases (PostgreSQL, MySQL 8+, SQL Server, SQLite 3.35+) support CTEs.

SQL in Application Code

SQL embedded in application code has additional formatting considerations:

Tagged template literals (JavaScript/TypeScript):

// Using a tagged template literal with a library like sql-template-strings
const result = await db.query(sql`
  SELECT
    u.id,
    u.email,
    COUNT(o.id) AS order_count
  FROM users u
  LEFT JOIN orders o ON u.id = o.user_id
  WHERE u.id = ${userId}
  GROUP BY u.id, u.email
`);

Python (f-strings + parameterisation):

# Always use parameterised queries — never f-string interpolation for user input
cursor.execute("""
    SELECT
        u.id,
        u.email,
        COUNT(o.id) AS order_count
    FROM users u
    LEFT JOIN orders o ON u.id = o.user_id
    WHERE u.id = %s
    GROUP BY u.id, u.email
""", (user_id,))

Never construct SQL by string concatenation of user input — this leads directly to SQL injection. Use parameterised queries or prepared statements. The placeholder syntax varies by driver: ? in SQLite/MySQL, %s in psycopg2, $1/$2 in node-postgres.

SQL Style Guides

Several well-known SQL style guides provide comprehensive conventions:

  • GitLab SQL Style Guide — lowercase keywords, underscored identifiers, explicit joins, no abbreviations. Used internally at GitLab and publicly documented.
  • Mazur SQL Style Guide — lowercase keywords, trailing commas, CTEs over subqueries. Popular in the analytics/dbt community.
  • Joe Celko's SQL for Smarties — uppercase keywords, right-aligned style, very strict. Traditional DBA perspective.
  • dbt Labs style — lowercase keywords, CTEs preferred, consistent with Mazur. Used by most dbt-based data teams.

For data engineering and analytics teams using dbt, the dbt/Mazur style (lowercase keywords, CTEs everywhere, trailing commas) has become a de facto standard. For application developers writing SQL in backend code, GitLab's guide or your team's own documented conventions work well.

SQL Linting and Formatting in CI

To enforce SQL style automatically:

  • SQLFluff — the most capable SQL linter and formatter. Supports multiple dialects, configurable rules, and CI integration. Install with pip install sqlfluff; run with sqlfluff fix ..
  • sqlfmt — a formatting-only tool (no linting) in the dbt style. Opinionated and fast. Install with pip install shandy-sqlfmt.
  • pgFormatter — a Perl-based formatter for PostgreSQL SQL with many options. Available as a VS Code extension.
  • prettier-plugin-sql — adds SQL formatting to Prettier, the JavaScript/TypeScript formatter. Useful if your codebase already uses Prettier.

FAQ

Common questions

What SQL dialects does the formatter support?

The formatter handles standard SQL and is compatible with MySQL, PostgreSQL, SQLite, SQL Server (T-SQL), and Oracle. It formats DML statements (SELECT, INSERT, UPDATE, DELETE), DDL (CREATE TABLE, ALTER TABLE, DROP), and common clauses (WHERE, GROUP BY, ORDER BY, HAVING, LIMIT, OFFSET, JOIN variants). Dialect-specific syntax (e.g. PostgreSQL $$ dollar quoting) is preserved as-is.

Does the formatter validate my SQL syntax?

No — the formatter is a pretty-printer, not a validator. It reformats the structure without executing the query or connecting to a database. Syntax errors in your SQL will still be formatted as best as possible; they will not be detected or reported. Use your database client or an online SQL validator to check for syntax errors.

Can I choose between uppercase and lowercase keywords?

Yes. The keyword case option lets you output SQL keywords in UPPER CASE (SELECT, FROM, WHERE), lower case (select, from, where), or preserve the original casing from your input. Most style guides recommend uppercase keywords to visually distinguish them from identifiers, but team conventions vary.

How does the formatter handle comments?

Both single-line (-- comment) and multi-line (/* comment */) SQL comments are preserved in place. The formatter does not strip or reorder comments — they stay attached to the line or clause they preceded.

What indentation options are available?

You can choose 2-space, 4-space, or tab indentation. The formatter increases indentation for clauses inside parentheses (subqueries, function arguments, IN lists) and aligns JOIN conditions with their ON clause.

Does the formatter change my query logic?

No. The formatter is purely cosmetic — it adds or removes whitespace and newlines, and optionally changes keyword case. It never reorders clauses, rewrites expressions, or adds/removes parentheses. The formatted output is semantically identical to the input.

Can it format very long or minified SQL?

Yes — that is the primary use case. Paste a single-line minified query or a multi-page stored procedure and the formatter will add newlines, indentation, and consistent spacing throughout. There is no length limit enforced by the tool.

Is my SQL sent to a server?

No. All formatting runs entirely in your browser using JavaScript. Your queries are never transmitted, stored, or logged. You can use this tool offline and it works identically.

More in Developer Tools