Code Beautifier
SQL & Databases

SQL formatting style guide for 2026

A house style for SQL that survives code review: keyword case, one clause per line, comma placement, aliasing, CTEs over nesting, and what to automate.

SQL has no official style. Every team that writes more than a handful of queries ends up with one anyway, usually by accident, usually inconsistent, and usually argued about in code review long after the query worked. This is the style we use and recommend, with the reasoning, so you can adopt it or disagree with it on purpose.

The rules are ordered by how much they matter for reading a query you did not write.

One clause per line, keywords at the left margin

The single most useful rule. SELECT, FROM, JOIN, WHERE, GROUP BY, HAVING, ORDER BY, and LIMIT each start a new line at the same indentation. The eye scans the left margin and sees the shape of the query before reading a single expression.

SELECT
  u.id,
  u.email,
  COUNT(o.id) AS order_count
FROM users AS u
LEFT JOIN orders AS o ON o.user_id = u.id
WHERE u.active = true
GROUP BY u.id, u.email
HAVING COUNT(o.id) > 3
ORDER BY order_count DESC
LIMIT 100;

A query written as one long line hides its structure; a query with the clauses stacked reveals it, including the clauses that are missing.

Uppercase keywords, lowercase everything else

SELECT, not select; users, not Users. Keywords in uppercase are a visual category: they are the grammar, and everything in lowercase is your data. This is the convention most style guides converge on, and it is the one your formatter should enforce so nobody has to type it.

Identifiers stay lowercase with underscores — order_count, created_at — because that is what PostgreSQL folds unquoted identifiers to, and mixed-case identifiers force quoting in every query forever after.

Commas at the end of the line, one column per line

Leading commas (, email) have a following: they make it easy to comment out the last column. Trailing commas make the list read like prose and match every other language you write. We use trailing, and we solve the comment-out problem by never leaving a trailing comma before FROM — which is exactly the mistake that produces syntax error at or near "," in PostgreSQL.

One column per line once the list has more than two or three entries. SELECT id, name FROM users is fine on one line; six columns are not.

Always alias, and alias with AS

Every table gets a short alias, and every derived column gets a name. AS is optional in most dialects and mandatory in our style, because SELECT total revenue FROM ... is legal SQL that silently aliases total to revenue, and that bug has cost real money. Writing AS makes the intent unmissable.

Alias tables with a meaningful abbreviation (users AS u, orders AS o), not a single letter chosen by position (a, b, c).

CTEs over nested subqueries

A query with a subquery inside a subquery reads inside-out. A WITH clause reads top-down, each step named:

WITH active_users AS (
  SELECT id, email
  FROM users
  WHERE active = true
),
recent_orders AS (
  SELECT user_id, COUNT(*) AS order_count
  FROM orders
  WHERE created_at > now() - interval '30 days'
  GROUP BY user_id
)
SELECT au.email, ro.order_count
FROM active_users AS au
JOIN recent_orders AS ro ON ro.user_id = au.id;

The performance argument against CTEs — that PostgreSQL treated them as optimisation fences — has been obsolete since version 12, which inlines them by default. Readability wins.

Explicit JOINs, with the condition on the same line

FROM a, b WHERE a.id = b.a_id is a join written as a filter. Use JOIN ... ON so the relationship and the filter are separated, and put the ON condition on the same line as the JOIN unless it has several parts. Name the join type: INNER JOIN when you mean inner, LEFT JOIN when you mean left. Bare JOIN is inner in every dialect, but writing the word removes a question from the reviewer's mind.

What the dialect changes

The rules above are dialect-independent. What is not:

  • Identifier quoting. PostgreSQL uses "order", MySQL uses `order`, SQL Server uses [order]. Avoid reserved words as names and you rarely need any of them.
  • Pagination. LIMIT in PostgreSQL, MySQL, and SQLite; TOP or OFFSET ... FETCH in T-SQL.
  • String escaping. Standard SQL doubles a quote inside a string ('O''Brien'); MySQL also accepts a backslash. Use the standard form, which is what Unclosed quotation mark is usually about.

Set the dialect in your formatter rather than letting it guess.

What to automate

Everything above except the aliasing and the CTE structure is mechanical, and mechanical rules should never be enforced by a human in review. SQL Formatter applies keyword case, clause-per-line layout, indentation, and comma placement per dialect; paste a query from an ORM log and it comes back in the house style. SQL Minifier does the reverse for the cases where a query has to live on one line — a log message, a config value, an HTTP header.

The one thing not to automate is meaning. A formatter can lay out WHERE a = 1 OR b = 2 AND c = 3 beautifully and it will still evaluate AND before OR. Parenthesise compound conditions by hand, every time.

The full rule set, with the reasoning compressed to one line each, is on the SQL style guide cheat sheet.