·8 min read·Developer Tools

SQL Formatting Best Practices: Write Readable Queries

Learn SQL formatting standards that make queries readable and maintainable. Covers indentation, keyword casing, JOIN alignment, subquery formatting, and team style guides.

Try our free SQL Formatter

Format and beautify SQL queries with proper indentation and keyword styling.

Open Tool

Why SQL Formatting Matters

SQL is one of the oldest programming languages still in daily use, and unlike Python or Go, it has no enforced formatting rules. This means the same query can be written in dozens of ways that all produce identical results but vary wildly in readability. Consider this real-world query crammed into a single line:

select u.id,u.name,u.email,o.total,o.created_at from users u inner join orders o on u.id=o.user_id where o.status='completed' and o.total>100 order by o.created_at desc limit 50;

Now compare it with the formatted version:

SELECT
    u.id,
    u.name,
    u.email,
    o.total,
    o.created_at
FROM users AS u
INNER JOIN orders AS o
    ON u.id = o.user_id
WHERE o.status = 'completed'
    AND o.total > 100
ORDER BY o.created_at DESC
LIMIT 50;

Both queries return the same data. But the formatted version is immediately scannable. You can see the selected columns, the join condition, the filters, and the sort order at a glance. In a code review, the formatted version takes seconds to understand; the one-liner requires mental parsing that wastes time and invites bugs to slip through.

Poorly formatted SQL leads to real-world problems: missed conditions during code review, accidental data mutations from misread WHERE clauses, duplicated logic because developers could not quickly understand an existing query, and slow onboarding for new team members who inherit a codebase full of dense one-liners.

Formatting is not about aesthetics. It is about reducing the cognitive load of reading SQL so your team can move faster, catch bugs earlier, and maintain queries over time. Our SQL Formatter can transform any messy query into a clean, standardized layout in one click.

Keyword Casing and Indentation

The most fundamental SQL formatting decision is whether to uppercase keywords. The overwhelming consensus across style guides is: uppercase all SQL keywords. This includes SELECT, FROM, WHERE, JOIN, ON, AND, OR, ORDER BY, GROUP BY, HAVING, INSERT, UPDATE, DELETE, and all other reserved words.

Why does casing matter? Because it creates a visual distinction between the SQL language structure and your application-specific identifiers (table names, column names, aliases). When scanning a long query, uppercase keywords act as signposts that guide your eye to the important structural elements.

Avoid
select name, email
from users
where active = true
Preferred
SELECT name, email
FROM users
WHERE active = TRUE

For indentation, use 2 or 4 spaces consistently. Never use tabs in SQL files, as tab width varies across editors and tools, causing alignment to break. Each major clause (SELECT, FROM, WHERE, GROUP BY, ORDER BY) should start at the same indentation level. Items within a clause (column lists, conditions, join predicates) should be indented one level deeper.

Some teams use right-aligned keywords (aligning SELECT, FROM, and WHERE so the body starts at the same column). While visually tidy, this style can be harder to maintain manually and is less common in modern tooling. The left-aligned style, where every keyword starts at column 1, is simpler and more widely supported by formatters.

SELECT and Column Formatting

When a SELECT statement returns more than two or three columns, place each column on its own line. This makes it trivial to see which columns are included, add or remove a column, and review diffs in version control.

-- One column per 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 AS u

A popular debate is leading commas vs trailing commas. With trailing commas, each line ends with a comma. With leading commas, the comma appears at the start of the next line:

Trailing Commas
SELECT
    id,
    name,
    email,
    created_at
FROM users
Leading Commas
SELECT
    id
    , name
    , email
    , created_at
FROM users

Leading commas have a practical advantage: commenting out the last column does not cause a syntax error from a dangling comma. They also make git diffs cleaner because adding a new column only changes one line. However, trailing commas are more intuitive for most developers and more common in modern style guides like the dbt style guide. Choose one style and enforce it consistently.

Always use meaningful aliases with the AS keyword. Write SUM(o.total) AS lifetime_value instead of SUM(o.total) ltv. The explicit AS keyword clarifies that this is an alias, not an accidental missing comma.

JOIN and WHERE Clause Layout

Each JOIN should start on its own line, with the ON condition indented beneath it. Always specify the join type explicitly (INNER JOIN, LEFT JOIN) rather than using the bare JOIN keyword, even though they are equivalent. Being explicit prevents confusion about whether a join is inner or outer.

SELECT
    u.name,
    o.order_number,
    p.product_name,
    oi.quantity,
    oi.unit_price
FROM users AS u
INNER JOIN orders AS o
    ON u.id = o.user_id
INNER JOIN order_items AS oi
    ON o.id = oi.order_id
LEFT JOIN products AS p
    ON oi.product_id = p.id
WHERE o.status = 'completed'
    AND o.created_at >= '2026-01-01'
    AND p.category = 'electronics'

For WHERE clauses with multiple conditions, place each condition on its own line with the logical operator (AND or OR) at the beginning of the line, not at the end. This pattern makes it easy to scan the list of conditions and spot the logical operator immediately:

Harder to Read
WHERE o.status = 'completed' AND
o.total > 100 AND
u.country = 'US' OR
u.country = 'CA'
Clear Structure
WHERE o.status = 'completed'
    AND o.total > 100
    AND (
        u.country = 'US'
        OR u.country = 'CA'
    )

Notice how the parenthesized OR group in the formatted version makes operator precedence explicit. The unformatted version is actually a logic bug: without parentheses, AND binds tighter than OR, so the query would return all Canadian users regardless of order status. Good formatting surfaces logic errors like this.

Subqueries and CTEs

Subqueries should be indented one level inside their parentheses. If a subquery is more than a few lines long, strongly consider refactoring it into a Common Table Expression (CTE) using the WITH clause instead.

Here is a subquery that is still manageable inline:

SELECT
    u.name,
    u.email
FROM users AS u
WHERE u.id IN (
    SELECT o.user_id
    FROM orders AS o
    WHERE o.total > 500
        AND o.created_at >= '2026-01-01'
)

Now compare it with the CTE approach, which is preferable for complex logic:

WITH high_value_orders AS (
    SELECT
        user_id,
        COUNT(*) AS order_count,
        SUM(total) AS total_spent
    FROM orders
    WHERE total > 500
        AND created_at >= '2026-01-01'
    GROUP BY user_id
    HAVING COUNT(*) >= 3
),

active_subscribers AS (
    SELECT user_id
    FROM subscriptions
    WHERE status = 'active'
        AND plan = 'premium'
)

SELECT
    u.name,
    u.email,
    hvo.order_count,
    hvo.total_spent
FROM users AS u
INNER JOIN high_value_orders AS hvo
    ON u.id = hvo.user_id
INNER JOIN active_subscribers AS sub
    ON u.id = sub.user_id
ORDER BY hvo.total_spent DESC;

CTEs offer several formatting advantages. Each CTE has a descriptive name that documents its purpose. The logic flows top-to-bottom, like reading a story. The final SELECT statement is simple and focuses on assembly rather than computation. And each CTE can be tested independently by running it in isolation.

Format CTEs with a blank line between each one, the WITH keyword on its own line, and each CTE body indented inside its parentheses. The comma separating CTEs should go at the end of the closing parenthesis or on its own line.

Team Style Guides and Linters

Manual formatting is unsustainable at scale. For teams that write SQL daily, automated tooling is essential. Here are the most widely used options:

  • sqlfluff -- The most popular open-source SQL linter and auto-formatter. It supports over 15 SQL dialects (PostgreSQL, MySQL, BigQuery, Snowflake, and more), integrates with CI/CD pipelines, and is configurable via a .sqlfluff config file. Run sqlfluff fix query.sql to auto-format.
  • pg_format -- A PostgreSQL-specific formatter written in Perl. Excellent for teams that use PostgreSQL exclusively. It handles PL/pgSQL function bodies and complex PostgreSQL syntax well.
  • sqlfmt -- A newer opinionated formatter that prioritizes consistency over configurability, similar to how Prettier works for JavaScript. It formats in one canonical style with minimal configuration.
  • dbt style guide -- If your team uses dbt for data transformations, the official dbt Labs SQL style guide is an excellent starting point. It covers CTEs, naming conventions, and model organization alongside formatting rules.

To enforce formatting in your workflow, add sqlfluff to your CI pipeline as a pre-commit hook or GitHub Action. This ensures every SQL file in your repository is consistently formatted before it reaches code review. The initial setup takes an hour, but it eliminates formatting debates permanently.

Here is a minimal .sqlfluff configuration to get started:

[sqlfluff]
dialect = postgres
templater = raw
max_line_length = 120

[sqlfluff:indentation]
indent_unit = space
tab_space_size = 4

[sqlfluff:rules:capitalisation.keywords]
capitalisation_policy = upper

[sqlfluff:rules:capitalisation.functions]
capitalisation_policy = upper

For quick one-off formatting tasks, you do not need to install anything locally. Our SQL Formatter runs entirely in your browser and supports multiple SQL dialects. It is also useful for formatting SQL snippets before pasting them into documentation, Slack messages, or pull request descriptions. For data that comes back as JSON, you can also use our JSON Formatter to pretty-print API responses, and our Regex Tester to build and test patterns for SQL string matching.

Frequently Asked Questions

Should SQL keywords be uppercase?
Yes, uppercasing SQL keywords like SELECT, FROM, WHERE, and JOIN is the most widely adopted convention. It visually separates SQL syntax from table and column names, making queries easier to scan. Most style guides, including the dbt style guide, recommend uppercase keywords.
What is the best indentation for SQL?
Use 2 or 4 spaces consistently (never tabs). Indent column lists under SELECT, conditions under WHERE, and subqueries inside parentheses. The most important thing is consistency — pick one style and enforce it with a linter like sqlfluff.
How do I format nested subqueries?
Indent each subquery by one level inside its parentheses. For complex or deeply nested subqueries, refactor into CTEs (WITH clauses) instead. CTEs give each subquery a name, making the overall query much easier to read and debug.
Is there a standard SQL style guide?
There is no single official standard, but several widely adopted guides exist: Simon Holywell's SQL Style Guide, the dbt Labs style guide, and Mozilla's SQL style guide. Tools like sqlfluff and sqlfmt can automatically enforce your chosen style.

Format Your SQL Now

Paste any SQL query, get instant formatting with proper indentation, keyword casing, and alignment. Free, private, runs in your browser.

Open SQL Formatter

Related Tools