SQL doesn't care about whitespace — select id,name from t where x=1 runs exactly as well as its nicely indented equivalent. Formatting exists entirely for the next human who reads the query, whether that's a teammate reviewing a pull request or you in six months trying to figure out why a report is double-counting rows. A few conventions consistently make that job easier.
Keywords uppercase, identifiers as-written
SELECT, FROM, WHERE, JOIN in uppercase against lowercase table and column names creates instant visual contrast — your eye separates "SQL syntax" from "your data model" without reading a single word. It's the most widely adopted SQL convention for exactly this reason, dating back to when terminals didn't have syntax highlighting and this was the only contrast available. Syntax highlighting has mostly replaced the need for it visually, but the convention stuck because it also helps in places highlighting doesn't reach — a query pasted into a Slack message, a log line, a commit message.
One clause per line
Compare:
select u.id, u.name, count(o.id) as order_count from users u left join orders o on o.user_id = u.id where u.active = 1 and u.deleted_at is null group by u.id, u.name having count(o.id) > 5 order by order_count desc limit 20against the same query with each clause on its own line:
SELECT u.id,
u.name,
count(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE u.active = 1
AND u.deleted_at IS NULL
GROUP BY u.id,
u.name
HAVING count(o.id) > 5
ORDER BY order_count DESC
LIMIT 20Both run identically. The second one you can scan in about a second: what's selected, what it's joined against, what it's filtered by. The first one requires reading the whole line before any of that's clear. Note that the formatter left count( lowercase — it only touches recognized SQL keywords, never function or column names, so your own naming choices always survive a reformat untouched.
One column per line once a query gets wide
A three-column SELECT is fine on one line. Once you're past four or five — especially with expressions or aliases mixed in — putting each column on its own line pays off twice: it's easier to scan the full list, and it produces far cleaner git diffs. Adding a column to a one-line SELECT shows as a change to the entire line; adding it to a one-column-per-line list shows as a single added line, exactly like you'd want a diff to look.
Indent subqueries and CTEs to show nesting
A subquery or CTE body is a query inside a query — indenting it communicates that immediately, the same way indenting the body of an if statement does in any other language:
WITH active_users AS (
SELECT id
FROM users
WHERE active = 1
)
SELECT *
FROM orders
WHERE user_id IN (
SELECT id
FROM active_users
)Without the indentation, it's much harder to tell at a glance where the subquery ends and the outer query resumes.
Prefer explicit JOIN syntax over comma joins
FROM a, b WHERE a.id = b.a_id and FROM a JOIN b ON a.id = b.a_id can produce the same result, but the second one states the relationship where the join happens, not buried in a WHERE clause full of unrelated filters. It also makes it obvious at a glance whether a join condition is missing — a forgotten comma-join predicate silently produces a cross join, while a JOIN with no ON is a syntax error your database catches immediately.
Pick an indent width and don't mix it with tabs
2 spaces or 4, either is fine — what actually matters is picking one and having your whole team (or your whole codebase) use it consistently. Mixed tabs and spaces are the single most common cause of SQL that looks aligned in one editor and ragged in another.
Consistency matters more than any individual rule
None of the above is a law — some teams genuinely prefer lowercase keywords, or leading commas (, column at the start of the next line instead of a trailing comma at the end) because it makes a missing or extra comma easier to spot at a glance. Pick conventions and apply them uniformly; a codebase where every query is formatted differently is worse than one that consistently uses a convention you personally wouldn't have chosen. Consistent formatting is also what keeps code review diffs meaningful — when everyone's queries already look the same, a diff shows only the actual logic change, not incidental reformatting noise mixed in with it.
Automate it instead of relying on discipline
Manually maintaining consistent formatting across a team, or even just across your own queries over time, doesn't hold up — it's the same reason JavaScript projects run Prettier instead of asking everyone to remember the style guide. Run a formatter on save, in a pre-commit hook, or in CI, and the question of whose formatting style is "correct" stops being a code review discussion at all.
Try it yourself
Paste a messy query into SQL Formatter to see these conventions applied automatically, with uppercase/lowercase keyword and indent-size options. If you need to catch structural mistakes — unbalanced parens, a stray comma — before formatting, run it through SQL Query Validator first. Both run entirely in your browser; your SQL is never sent anywhere.