SQL Formatter_

A SQL formatter that knows what it does not know. Paste a query and it lays out clauses, indents subqueries and CTEs, cases keywords the way your team writes them, and puts commas where your style guide wants them — with dialect-aware handling for PostgreSQL dollar-quoting, MySQL backticks, and T-SQL bracket identifiers.

When the tokenizer meets something it cannot parse with confidence — an unterminated literal, an Oracle-style quoting construct, unbalanced parentheses — it refuses to reformat and tells you why, returning your SQL with only blank lines tidied. A query that has been silently altered is far worse than one that was left alone. Everything runs in this tab, which matters when the query names your production tables.

toolkit.codes/sql-formatter
Formatted_SQL
Paste SQL to format it
UTF-8
Ready
100% LOCAL

Laying out SQL without changing it

What a SQL formatter is for — and what it proves

Formatting rearranges whitespace and keyword casing so a query can be read: clauses at the left margin, column lists indented beneath them, joins and conditions on their own lines. It is a legibility operation, not a correctness one. A query that comes out beautifully arranged can still reference a column that does not exist, join on the wrong key, or scan a billion rows — the layout says nothing about any of that. Treat a formatted query the way you would treat tidied prose: easier to review, not yet reviewed. That distinction matters most in code review, where a diff full of reflowed whitespace hides the one changed predicate that deserved attention.

The dialect problem, stated plainly

Every SQL dialect quotes things differently, and a formatter that guesses wrong does not produce ugly output — it produces different SQL. PostgreSQL's dollar-quoted bodies ($$ … $$, $tag$ … $tag$) contain arbitrary text including semicolons and comment markers; MySQL escapes quotes with backslashes where the standard doubles them; T-SQL wraps identifiers in [brackets] with ]] as the escape. Pick the wrong rule and a string's contents get treated as code. This page handles those cases for the Standard, PostgreSQL, MySQL/MariaDB, T-SQL, and SQLite selections, and it does not claim Oracle's q'[…]' quoting or BigQuery's raw strings. Meeting one of those triggers the refusal path rather than a guess.

Casing, commas, indentation: conventions, not rules

Uppercase keywords date from terminals without syntax colouring, where SELECT had to stand out from column names by shape alone. Leading commas — putting the comma at the start of the next line — exist because they make it obvious when the last item is missing one, and because deleting a line then leaves valid SQL. Neither is correct in any technical sense; both are house style, and the point of exposing them here is that you can match whatever your repository already does instead of arguing with a tool. Set them once and the output slots into your codebase without a reformatting war in the next pull request.

Where the query goes, and the SSMS question

SQL is the worst thing to paste into a remote service: a real query names your schema, and its WHERE clause frequently contains a literal customer email or account number. Of the best-known online formatters, several process on their servers — the query travels, gets logged somewhere, and is out of your control. This page cannot do that: its Content-Security-Policy forbids the tool code from making network requests at all, and a test asserts it. On the two adjacent searches: people looking for a formatter for SSMS or for Postgres usually want an editor add-in — this is a browser page, not an SSMS extension, and saying so plainly is more useful than pretending. What it does give you is the same dialect awareness without installing anything, which is often enough for the query you are staring at right now.

How to use

  1. 01Paste the query, or use Upload_.sql to load a file — the bytes are read in your browser. Formatting runs on every keystroke and on every option change.
  2. 02Pick the dialect that matches your database. It changes how strings and identifiers are read, not just how they are displayed, so an inaccurate choice can trigger the refusal path rather than silently mangling a literal.
  3. 03Set keyword case, indent size, and comma placement to match your repository’s existing style, then Copy or Download the result.
  4. 04If the warning banner appears, the tokenizer refused to reformat and says why — fix the flagged construct (usually an unterminated quote) or switch dialect. The output box then holds your original SQL with only blank lines tidied.

Where a formatter earns its keep

Reading what the ORM generated

A logged query arrives as one 900-character line. Formatting is the difference between debugging it and giving up.

Input
SELECT t0.id, t0.name FROM users t0 LEFT JOIN…
Output
clauses on their own lines, joins aligned

A review diff that is all whitespace

Format both versions the same way first, and the diff shrinks to the predicate that actually changed.

Before review
format old.sql · format new.sql
Diff
one changed WHERE line instead of forty

Pasting a query into a ticket

Normalise it first so the next person reads the query, not your editor's wrapping.

Options
UPPER keywords · 2 spaces
Result
a query that reads the same for everyone

Keeping .sql files consistent

Migration files drift in style across a team; one setting brings them into line before commit.

Upload
001_add_index.sql
Download
formatted.sql, house style applied

Every option, on one query

OptionSettingWhat it produces from <code>select a, b from t where x = 1</code>
Keyword caseUPPER (default)SELECT a,FROM t — keywords shout, identifiers stay as written
Keyword caselower / Preserveselect a, … or exactly the casing you typed, untouched
Indent2 / 4 spacesContinuation lines under each clause get 2 or 4 spaces of padding
IndentTabOne tab per level — matches repositories that indent SQL with tabs
CommasTrailing (default)SELECT a, then b on the next line
CommasLeadingSELECT a then , b — a missing comma becomes obvious
MinifyOnOne line, comments dropped, optimizer hints kept, strings untouched
DialectStandard → SQLiteChanges how strings and identifiers are read; the wrong choice triggers the refusal path

Formatting is idempotent under every combination: running the output back through with the same settings returns it unchanged (asserted in tests).

Dialect differences that affect formatting

DialectIdentifier quotingString escapingPlaceholdersHandled here
Standard"double quotes"'' doubling?Yes
PostgreSQL"double quotes"'', E'\n', and dollar-quoting $$…$$ / $tag$…$tag$$1Yes — dollar-quoted bodies pass through byte-for-byte
MySQL / MariaDB`backticks`'' and backslash escapes \'?Yes — plus # line comments
T-SQL[brackets], ]] escape'', N'unicode'@paramYes
SQLiteall of "…", […], `…`'' doubling?, :nameYes
Oracle / BigQueryq'[…]', raw and triple-quoted stringsdialect-specificvariesNo — recognised and refused, never guessed

Refusing is the feature: when the tokenizer cannot be sure, you get your SQL back with only whitespace tidied and a message naming the construct.

Tips & best practices

  • Set the dialect before anything else — it decides how quotes are read, which is the one setting that can change meaning rather than appearance.
  • Format both sides before diffing two versions of a query; a whitespace-only diff hides the change you are looking for.
  • Leading commas pay off in long column lists that get edited often; trailing commas read better in short ones. Match the file you are editing, not your preference.
  • Keep optimizer hints exactly where they are — they are comments to a formatter but instructions to the planner, so this page carries them through minification too.
  • If the refusal banner mentions an unterminated string, look for an apostrophe in a literal (O’Brien) that needs doubling or escaping for your dialect.
  • Formatting is idempotent here, so it is safe to run in a pre-commit hook style workflow — the second pass never changes the first pass’s output.

Gotchas — where SQL formatters do damage

Dollar-quoted bodies get mangled by naive tools

A PostgreSQL function body between $$ markers is arbitrary text — semicolons, comment markers, whole nested statements. Formatters that tokenise without understanding dollar-quoting re-indent and re-case that text, and the function you deploy is no longer the function you wrote. This page treats the whole block as one opaque token and passes it through byte-for-byte.

Optimizer hints are comments until they are not

A tool that strips comments as noise will happily delete /*+ INDEX(t idx) */, and the query still runs — just with a different plan and a mystery regression. Hints survive both formatting and minification here for exactly that reason.

A formatted query is not a validated query

Nothing about layout checks table names, column existence, join keys, or types. This page never parses meaning, only structure, so a query it formats perfectly can still fail on execution or return the wrong rows. Format to read; test to trust.

Leading versus trailing commas is a team decision

Neither is more correct, and tools that impose one are picking a side in someone else’s style argument. What actually costs time is churn: a repository where half the files use each style produces diffs full of noise. Pick one, set it here, and be consistent.

Server-side formatters see your production data

Queries carry schema layout and often literal values from real records in their WHERE clauses. Several well-known online formatters process on their servers, which means the query is transmitted and may be logged. Check where a formatter runs before pasting anything real into it. This one only ever reads the query you typed, in the tab you typed it in.

Technical details

Dialects
Standard, PostgreSQL (dollar-quoting), MySQL/MariaDB (backticks, backslash escapes, # comments), T-SQL (bracket identifiers with ]] escape), SQLite
Not claimed
Oracle q’…’ quoting, BigQuery raw/triple-quoted strings, MySQL DELIMITER — recognised where possible and refused rather than guessed
Refusal path
Unterminated literals, comments or dollar-quotes, unsupported quoting constructs, and unbalanced parentheses return whitespace-only normalisation plus the reason — never reformatted SQL
Options
Keyword case (upper/lower/preserve), indent (2/4/tab), comma placement (trailing/leading), minify
Preservation
Comments and optimizer hints kept verbatim; string and quoted-identifier contents byte-identical; the non-whitespace token stream is unchanged by formatting (tested)
Idempotence
format(format(x)) === format(x) for every fixture across all 18 option combinations, asserted in tests
Scope
Layout only — no validation, linting, or optimisation. A dedicated SQL minifier page is planned on this same tokenizer
Limits
Past 300k characters the output pane stops drawing, so a generated monster of a query cannot lock the page up. Copy and Download are unaffected and always carry the complete result.

FAQ

How do I format a SQL query online?

Paste it above and set the dialect to match your database. The layout appears as you type; adjust keyword case, indent, and comma placement to your team’s style, then copy or download. No account, no upload — the query stays in this tab.

Which SQL dialects does this handle?

Standard, PostgreSQL, MySQL/MariaDB, T-SQL, and SQLite, including the quoting rules that actually differ: dollar-quoted bodies, backticks with backslash escapes, and bracket identifiers. Oracle and BigQuery quoting are deliberately not claimed; input using them is refused rather than guessed at.

Is there a SQL formatter for SSMS?

Not this — SSMS formatting comes from add-ins that install into the editor. This is a browser page you can use alongside any client, with the T-SQL dialect selected for bracket identifiers and @parameters. For in-editor formatting on every keystroke, an add-in is the right tool; for the query in front of you, this is faster than installing one.

Can formatting change what my query does?

It should never, and this page is built so that it cannot silently try: anything the tokenizer is unsure about triggers a refusal with a whitespace-only result and a stated reason. Comments, hints, string contents, and identifier casing all pass through untouched.

What about formatting dates in SQL?

That is a different job from formatting a query’s layout — it means date-to-text functions, which are per-dialect: TO_CHAR in PostgreSQL and Oracle, DATE_FORMAT in MySQL, FORMAT or CONVERT with a style code in T-SQL, and strftime in SQLite. This page lays out the query around them; it does not change how a date renders.

Can it minify SQL too?

Yes — the Minify toggle collapses the query to one line, dropping comments but keeping optimizer hints, since dropping a hint changes the execution plan. A dedicated minifier page is planned on the same tokenizer.