How to Format SQL Queries for Readability
· 5 min read
SQL has a way of growing into dense, unreadable walls of text. A query that started as a simple SELECT accumulates joins, conditions, and subqueries until nobody can parse it at a glance. Consistent formatting is the cheap fix, and it pays off most where it counts: in code review and in the next person's debugging session, which is often your own.
Why Formatting Matters in Review
When a reviewer opens a pull request containing a 40-line query crammed onto a handful of lines, they cannot reason about it. They cannot see which tables are joined, what the filter conditions are, or whether a subquery is correlated. Well-formatted SQL lets a reviewer scan the structure - the SELECT list, the FROM, each JOIN, the WHERE - as distinct visual blocks. That is the difference between a meaningful review and a rubber stamp. Formatting also produces cleaner diffs: when each column and condition sits on its own line, a one-line change shows up as a one-line diff instead of an unreadable rewrite of a packed line.
Keyword Casing
The oldest convention is uppercasing keywords - SELECT, FROM, WHERE, JOIN, GROUP BY - while keeping table and column names in lowercase or whatever case your schema uses. The point is contrast: uppercase keywords stand out from your identifiers, so the eye finds the clauses instantly. Whichever convention your team picks, the rule that matters is consistency. A codebase where half the queries shout and half whisper is harder to read than one that commits to either style.
Indenting Joins
Each JOIN should start on its own line, aligned with FROM, and its ON condition should be clearly attached. When you have several joins, this vertical layout lets you read the chain of tables top to bottom and immediately spot a missing join condition - the classic cause of an accidental cross join that returns millions of rows. Putting each join on its own line is not cosmetic; it is how you catch that bug by eye.
Indenting Subqueries
Subqueries are where unformatted SQL becomes truly impenetrable. A subquery should be indented one level deeper than the statement that contains it, so its boundaries are visually obvious. Common table expressions, the WITH clause, are usually the better choice for anything non-trivial precisely because they let you name and separate each step instead of nesting parentheses three deep. When you must nest, indentation is what keeps the inner query distinguishable from the outer one.
Format Before You Commit
The practical habit is to format SQL as the last step before committing, the same way you run a code formatter on your application code. This keeps the repository consistent regardless of who wrote the query or which editor they used, and it removes formatting noise from your diffs so reviewers see only real changes. Rather than reformatting by hand, paste the query into the SQL Formatter, which applies consistent casing and indentation in one pass. It runs entirely in your browser, so a query containing real table names, schema details, or embedded values is formatted locally and never uploaded - worth knowing when the SQL reflects production structure you would rather not paste into a random web service.
A Note on Dialects
SQL is not one language. PostgreSQL, MySQL, SQL Server, Oracle, and SQLite each have their own quirks - different quoting characters for identifiers, different functions, different syntax for things like LIMIT versus TOP. A formatter that understands your dialect will keep identifier quoting and dialect-specific keywords intact rather than mangling them. When you format, make sure the tool is treating the query as the right dialect, or at least confirm it has not altered anything dialect-specific.
The Short List
- Uppercase keywords, lowercase identifiers, and stay consistent.
- One column per line in the SELECT list for clean diffs.
- Each JOIN on its own line so missing conditions are obvious.
- Indent subqueries, and prefer CTEs for anything complex.
- Format as the final step before committing, every time.
Good SQL formatting will not make a slow query fast, but it will make every query easier to review, debug, and trust.