Cadmeo

SQL Formatter

Keyword-based formatting. It does not parse or validate the query.

Formatted
SELECT u.id, u.name, count(o.id) as orders
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE u.active = 1
  AND u.created_at > '2024-01-01'
GROUP BY u.id, u.name
HAVING count(o.id) > 5
ORDER BY orders desc
LIMIT 20

The SQL formatter takes a query written on one line and breaks it before each clause keyword, so the structure becomes visible. It normalises keyword case at the same time, and indents AND and OR under the condition they belong to. The minify direction does the reverse, collapsing a formatted query back to one line for a config file or a log. It is a formatter, not a parser. It does not validate the query or understand what it does.

How it works

  • Whitespace is collapsed first, so a query that is already badly wrapped is normalised before being re-broken.
  • Keywords are matched case-insensitively and rewritten to your chosen case.
  • A line break is inserted before each clause keyword: FROM, WHERE, JOIN, GROUP BY, ORDER BY, HAVING, LIMIT and the rest.
  • AND and OR are indented, because they continue the previous clause rather than starting a new one.
  • Minifying collapses all whitespace to single spaces and drops both comment styles, leaving string literals untouched.

Because it works on keywords rather than a parse tree, a column or alias named after a keyword will be reformatted as one. That is the trade-off for a formatter that handles any SQL dialect without knowing which one it is looking at.

Examples

A one-line query

SQL

select u.id, count(o.id) from users u left join orders o on o.user_id = u.id where u.active = 1 group by u.id

Result

SELECT u.id, count(o.id)
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE u.active = 1
GROUP BY u.id

Five clauses on five lines. LEFT JOIN is matched as a single keyword rather than being broken between LEFT and JOIN.

Multiple conditions

SQL

where u.active = 1 and u.created_at > '2024-01-01'

Result

WHERE u.active = 1
  AND u.created_at > '2024-01-01'

AND is indented under WHERE, which makes it obvious at a glance how many conditions a query has.

Frequently asked questions

Does it validate my SQL?

No. It reformats text based on keyword matching and never parses the query, so a syntactically broken query is reformatted just as happily as a valid one. Run it against your database to find out whether it works.

Which SQL dialect does it support?

All of them, in the limited sense that it only looks for keywords common to nearly every dialect. Dialect-specific syntax passes through untouched rather than being reformatted, which is usually the safer outcome.

What happens if a column is named after a keyword?

It gets reformatted as a keyword. A column called "order" or "limit" will have its case changed and may trigger a line break. This is the cost of keyword matching without a parser, and it is why the output should be read before being committed.

Should I use uppercase keywords?

It is the long-standing convention and makes structure scannable in a query mixed with lowercase identifiers. Many modern style guides now prefer lowercase throughout. Both options are here because the choice is genuinely a team preference.

What does minifying a query actually remove?

Line breaks, indentation and both comment styles, the double-hyphen line comment and the slash-star block. Text inside quotes is left exactly as written, so a string containing two hyphens is not mistaken for a comment. It is for getting a query into a single-line config value or a log entry, not for performance: the database parses either form identically.