Sharon Ben-Moshe is the founder of sqlfmt, a browser-based SQL formatter and validator with misspelled-keyword suggestions across PostgreSQL, MySQL, SQLite, SQL Server, and BigQuery.
Eight SQL formatting best practices — keyword casing, comma style, explicit JOINs, CTE usage, and keyword typo checking — with before-and-after examples.
Quick answer
Readable SQL uses uppercase keywords, one clause per line, consistent indentation, and a decided comma convention (leading or trailing — pick one). Alias every computed column, write explicit JOIN types, flatten deep subqueries into CTEs, and spell-check your keywords. A SQL formatter like sqlfmt enforces all of these automatically so you can focus on query logic instead of whitespace.
FAQs
Does SQL keyword casing affect how queries run?
No — SQL keywords are case-insensitive in every major database. SELECT, select, and Select all parse identically in PostgreSQL, MySQL, SQLite, SQL Server, and BigQuery. The uppercase convention is purely for human readability, not a parser requirement.
Should I use leading or trailing commas in SQL?
Both are valid. Trailing commas (at the end of each line) match conventions from most programming languages and are the default in most formatters. Leading commas (at the start of each line) make a missing comma visually obvious in long column lists. The only rule that matters is picking one and applying it consistently across your codebase.
What is a CTE in SQL and when should I use one?
A CTE (Common Table Expression) is a named temporary result set defined with a WITH clause at the start of a query. Use a CTE when a subquery is referenced more than once, when nesting more than two levels deep makes logic hard to follow, or when naming an intermediate result improves clarity. CTEs are supported in PostgreSQL, MySQL 8+, SQLite 3.35+, SQL Server, and BigQuery.
How do I catch SQL keyword typos before they fail at runtime?
Use a SQL linter or formatter with a built-in keyword checker. sqlfmt checks every keyword against the target dialect's word list and suggests corrections. Without tooling, a typo like SLECT produces a 'syntax error at or near' message from PostgreSQL or error 1064 from MySQL — both of which point to the character after the typo, not the typo itself.
How do I enforce SQL formatting standards across a team?
Add a SQL formatter to your pre-commit hooks or CI pipeline so formatting is checked on every pull request. Document your chosen conventions — comma style, indentation depth, keyword casing — in a short team style guide and let the formatter enforce them. This removes formatting debates from code review and keeps discussions focused on query logic.
Try it now
Paste your SQL into sqlfmt — format, validate, and catch typos free in your browser.
Unformatted SQL is easy to write and hard to read. A query that spans 40 lines — no indentation, no keyword casing, no line breaks between clauses — looks intimidating even to the developer who wrote it a week ago.
These eight rules are the SQL formatting conventions that the most readable production queries share. Each one includes a before-and-after example. None of them are controversial — except one, which we will settle fairly.
1. Use Uppercase for SQL Keywords
The most universal SQL convention: keywords in UPPERCASE, identifiers in lowercase. PostgreSQL, MySQL, SQLite, SQL Server, and BigQuery all treat keywords as case-insensitive at parse time — but uppercase makes the clause structure scannable at a glance. See the PostgreSQL keywords reference for the full reserved word list.
Before: lowercase keywords, single line
select id, email, created_at from users where active = 1 order by created_at desc
After: uppercase keywords, one clause per line
SELECT id, email, created_atFROM usersWHERE active = 1ORDER BY created_at DESC
The capitalization contrast makes the clause structure scannable without reading every word. Most SQL formatters, including sqlfmt, uppercase keywords by default.
2. Put Each Clause on Its Own Line
The single biggest readability win costs nothing: a newline before each top-level clause. SELECT, FROM, WHERE, JOIN, GROUP BY, HAVING, ORDER BY, and LIMIT each start a new line. This keeps any one line short and makes it obvious which part of the query you are reading.
Before: entire query on one line
SELECT id, name, email FROM users JOIN orders ON users.id = orders.user_id WHERE orders.status = 'paid' GROUP BY users.id ORDER BY users.id
After: one clause per line
SELECT users.id, users.name, users.emailFROM usersJOIN orders ON users.id = orders.user_idWHERE orders.status = 'paid'GROUP BY users.idORDER BY users.id
3. Indent Consistently — Two or Four Spaces, Never Tabs
Indent the column list after SELECT, the conditions after WHERE, and anything inside a subquery or CTE one level deeper. Two spaces or four spaces — choose one and never mix them with tabs. Tabs render differently in every editor and break diffs.
4. The Leading vs. Trailing Comma Debate (and How to End It)
This is the one everyone argues about. Trailing commas — the default in most formatters — match punctuation conventions from most programming languages:
Trailing commas (the default)
SELECT id, email, created_atFROM users
Leading commas
SELECT id , email , created_atFROM users
Leading commas make it visually obvious when a comma is missing — the gap in the visual column stands out. Trailing commas feel more natural to most developers. Both styles produce identical SQL. The rule is: pick one and enforce it automatically with a formatter. sqlfmt supports both.
5. Alias Every Column You Select
In joins and aggregations, unlabeled expressions become generic column names like "expr1" or the raw function call text. Explicit aliases (AS column_name) make results self-documenting and keep downstream code stable if the underlying query changes.
6. Always Write Explicit JOIN Types
A bare JOIN is an implicit INNER JOIN — but a reader who doesn't know that will wonder which rows are included. Writing INNER JOIN, LEFT JOIN, or RIGHT JOIN explicitly tells the reader immediately whether null rows are possible in the result.
7. Flatten Deep Subqueries into CTEs
Subqueries nested more than two levels deep are hard to read and debug. Common Table Expressions (CTEs) let you name each logical step and read the query top-to-bottom instead of inside-out. CTEs are supported in PostgreSQL, MySQL 8+, SQLite 3.35+, SQL Server, and BigQuery.
8. Spell-Check Your SQL Keywords
Formatting fixes whitespace; a keyword spell-checker catches SLECT, FORM, GROPU BY. These fail at runtime with a generic 'syntax error at or near' message (see our PostgreSQL guide) or MySQL's error 1064 (see our MySQL guide) — the parser sees an unexpected token and cannot tell a typo from a real syntax error.
sqlfmt's built-in typo checker flags misspelled keywords and suggests the correct spelling. It uses position-aware analysis — a table named form or a column named select_id won't get flagged. Try it free at sqlfmt.app; the Pro plan adds live formatting as you type.
SQL Formatting Checklist
Run through these eight checks before committing SQL to version control or submitting a query for review:
Keywords are UPPERCASE; table names, column names, and aliases are lowercase.
Each clause (SELECT, FROM, WHERE, JOIN, GROUP BY, ORDER BY) starts on its own line.
Indentation is two or four spaces — no tabs, no mixing.
Commas are consistently leading or consistently trailing across the file.
Every computed column and aggregate function has an explicit AS alias.
Every JOIN has an explicit type: INNER JOIN, LEFT JOIN, RIGHT JOIN, or FULL OUTER JOIN.
Subqueries nested more than two levels deep are extracted into named CTEs.
Consistent SQL formatting is the cheapest form of code review. Eight rules — uppercase keywords, one clause per line, consistent indentation, a decided comma style, explicit aliases, explicit JOIN types, CTEs over deep subqueries, and keyword spell-checking — cover most of what separates readable SQL from opaque SQL.
The easiest way to enforce all of these automatically is to run a formatter before you commit. sqlfmt handles the formatting and keyword-typo pass in one step, across PostgreSQL, MySQL, SQLite, SQL Server, and BigQuery.