Formatting SQL in Code Reviews
Unformatted SQL is one of the most common sources of friction in code reviews. A developer pastes a query written in a single line, a reviewer asks for better formatting, and the discussion spirals into personal preferences rather than meaningful feedback about logic and performance. Establishing clear SQL formatting standards eliminates this cycle and keeps reviews focused on what matters.
Why SQL Formatting Deserves Its Own Standard
Most teams enforce style guides for their primary programming language — linters catch missing semicolons, inconsistent quotes, and wrong indentation in JavaScript or Python. SQL, however, often lives outside those pipelines. It sits in migration files, ORM scopes, raw query strings, and analytics notebooks, bypassing the linter entirely.
Poorly formatted SQL creates real problems beyond aesthetics:
- Hidden bugs. A missing comma in a SELECT list or an accidentally commented-out WHERE clause is much harder to spot in a wall of unformatted text.
- Review slowdown. Reviewers spend cognitive bandwidth parsing layout instead of evaluating JOIN logic, index usage, or N+1 risks.
- Merge conflicts. When multiple developers edit the same unformatted query without consistent line breaks, Git produces tangled conflicts that are painful to resolve.
Setting Up a Team SQL Style Guide
A practical SQL style guide does not need to be exhaustive. Focus on the rules that have the highest impact on readability and review efficiency.
Core Rules to Define
| Rule | Example | Why It Matters |
|---|---|---|
| Keyword casing | SELECT, FROM, WHERE (uppercase) | Keywords stand out from identifiers |
| Line breaks per clause | Each JOIN, WHERE, ORDER BY on a new line | Makes query structure scannable |
| Indentation | 4 spaces per nesting level | Shows subquery and CTE boundaries |
| Comma placement | Trailing or leading — pick one | Consistency across all files |
| Alias style | AS keyword always, or never | Prevents ambiguous shorthand |
| Semicolons | Always terminate statements | Required by some databases, avoids ambiguity |
Document your choices in a short markdown file in the repository root. Reference it in pull request templates so authors can self-check before requesting review.
Automating Formatting Checks in CI
Style guides that rely on manual enforcement inevitably drift. The most effective approach is to add a formatting check to your CI pipeline that fails the build on violations.
Using sqlfluff
sqlfluff is a dialect-aware SQL linter and formatter that supports PostgreSQL, MySQL, BigQuery, Snowflake, and more. Configure it with a .sqlfluff file:
[sqlfluff]
dialect = postgres
exclude_rules = L034 # allow mixed select targets
[sqlfluff:layout:type:comma]
line_position = trailing
[sqlfluff:layout:type:select_clause]
line_position = leading
Run it in CI:
# .github/workflows/sql-lint.yml
name: SQL Lint
on: [pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install sqlfluff
- run: sqlfluff lint queries/ --dialect postgres
For auto-fixing, use sqlfluff fix locally. In CI, keep it as a check-only step so developers are forced to run the fix command and review the changes before pushing.
Pre-commit Hooks
For faster feedback, add a pre-commit hook:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/sqlfluff/sqlfluff
rev: 3.1.1
hooks:
- id: sqlfluff-fix
args: [--dialect, postgres]
This catches formatting issues before they even reach the remote repository, saving CI minutes and review rounds.
Common Formatting Issues to Watch For
Even with automation, certain patterns slip through and deserve explicit attention in reviews:
- Implicit JOINs. Queries that use comma-separated tables (
FROM users, orders) instead of explicitJOINsyntax should be flagged. Explicit JOINs make the relationship between tables clear and reduce the risk of accidental cross joins. - **SELECT *. In production queries, wildcard selects should be justified. They break when columns are added or reordered and prevent covering indexes from working efficiently.
- Missing table aliases. Ambiguous column references without table aliases cause errors in some databases and confusion in all of them.
- Over-nested subqueries. CTEs (WITH clauses) improve readability over deeply nested subqueries. Encourage their use in the style guide.
Key Takeaways
- Unformatted SQL wastes review time and hides logic bugs that structured formatting exposes immediately.
- Define a minimal set of formatting rules — keyword casing, line breaks, indentation, comma placement — and document them in your repository.
- Automate enforcement with a SQL linter like
sqlfluffin CI and pre-commit hooks. - Use code reviews to catch semantic issues — implicit JOINs, SELECT *, and over-nested subqueries — rather than debating indentation preferences.
Try It Yourself
Need to clean up SQL before a review? Drop your raw queries into the SQL Formatter to apply consistent keyword casing, indentation, and line breaks in seconds.