Uppercase keywords, consistent indentation, CTEs and window functions handled correctly. Nothing leaves your browser.
Runs in your browser. If a segment can't be parsed with confidence, it's left exactly as you wrote it.
This formatter tokenizes your query character by character before it reformats anything: strings, comments, quoted identifiers, numbers, operators, and words are each classified first, then only whitespace and line breaks around known clause keywords are changed. A string literal that happens to contain the word SELECT stays exactly as written, quotes and casing intact, because it was tokenized as a string, not as a keyword. If a query has an unbalanced paren or an unterminated string, the tool doesn't try to guess your intent; it passes the malformed part through rather than mangling it further.
select u.id, o.total from users u inner join orders o on u.id = o.user_id where o.total > 100 and u.active = 1 order by o.total desc
becomes:
SELECT u.id, o.total FROM users u INNER JOIN orders o ON u.id = o.user_id WHERE o.total > 100 AND u.active = 1 ORDER BY o.total DESC
A CTE's inner query gets its own indent level relative to the parenthesis it lives inside, so a chain of two or three CTEs stays readable instead of collapsing into one wall of text:
WITH recent AS ( SELECT * FROM events WHERE ts > '2026-01-01') SELECT count(*) FROM recent
Window functions and their PARTITION BY / ORDER BY clauses stay inside the function's parentheses rather than breaking onto new top-level lines, since a comma inside a function call or argument list is deliberately left inline instead of triggering a new line: ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) formats as one readable unit, not a list broken apart by every comma it contains.
Line comments (--) and block comments (/* ... */) are recognized as their own token type and never touched beyond being kept on the line they started on. A CASE ... WHEN ... THEN ... ELSE ... END block is tracked as its own nesting level so its internal keywords don't trigger the same line breaks a top-level WHEN would outside a CASE expression, which is a common way naive regex-based formatters break a query that looks fine until you run it.
This is the free, no-key layer of formatting: consistent casing, consistent indentation, one clause per line. It does not rewrite your query's logic, rename anything, or suggest a better join. QueryFlow's Ask panel, using your own API key against a model like Claude Sonnet 5 or GPT-6, can go further: explain what a query does, suggest an index, or rewrite a subquery as a CTE. This tool is the mechanical half of that; Ask is the half that requires actually understanding what the query is for.
No. Tokenizing and formatting both happen in JavaScript in your browser. Nothing you paste is transmitted anywhere.
It's designed not to. Only whitespace and line breaks around recognized clause keywords change; strings, comments, identifiers, and operators are passed through as tokenized, unchanged.
Yes. A parenthesized SELECT or WITH gets its own indent level relative to where it's nested, so multi-CTE queries stay readable.
Commas inside parentheses (function calls, value lists) are kept inline on purpose. Only top-level commas, like a SELECT list or column list, start a new line.
This is rule-based formatting only: casing and layout. Ask panel uses your own model key to actually reason about a query, like explaining it or suggesting a rewrite.
QueryFlow's Ask panel explains and rewrites SQL with your own model key.
No credit card. 14 days. Cancel in one click.