Calci.inCalculate Today for a Better Tomorrow

SQL Formatter

Beautify or minify SQL queries, nothing uploaded

Free, no sign-up · Reviewed

The guide

How the SQL formatter lays out a query

The layout rules the SQL formatter follows for clauses, columns, joins, conditions, subqueries and CASE, how it keeps the query's meaning unchanged, and when to minify instead.

Last reviewed · 1,281 words

In short

  • Each clause keyword (SELECT, FROM, WHERE, GROUP BY, ORDER BY and so on) starts a line, and what belongs to it is indented underneath, one column per line.
  • Joins and each AND or OR condition get their own line; subqueries are indented inside their brackets; CASE gets one line per WHEN.
  • Only spaces, line breaks and keyword case change. Our test splits the query into words before and after formatting and checks they match, for every sample and every keyword-case setting.
  • It works across MySQL, PostgreSQL, SQL Server and SQLite syntax, and formatted 2,000 statements, 868 KB of SQL, in about 0.4 seconds in our test.
  • Nothing is uploaded, so queries from work are safe to paste.

A query copied out of application logs, an ORM's debug output or a colleague's message usually arrives as one long line. It runs, but nobody can review it: which conditions belong to the join, which to the WHERE clause, where the subquery ends. A SQL formatter rewrites the same query with line breaks and indentation that show its structure. This page does that in your browser. Here are the rules it follows, and why the result always means exactly what the original meant.

How to format a SQL query

  1. Paste the query into the box, or open a .sql file. Several statements separated by semicolons are fine.
  2. Read the formatted SQL on the right.
  3. Copy it or download it as a .sql file.

Options: Format or Minify; keywords in UPPER case, lower case or as typed; and an indent of 2 spaces, 4 spaces or a tab.

The layout, rule by rule

The style is the one most teams and most formatting tools settle on, because it makes the parts of a query line up.

Clause keywords start a line at the left. SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT, INSERT INTO, VALUES, UPDATE, SET, DELETE FROM, WITH and RETURNING each begin a new line at the current level.

What belongs to a clause is indented under it. The columns of a SELECT, the tables of a FROM, the conditions of a WHERE all sit one indent further in.

Lists go one item per line. A comma in a SELECT, GROUP BY, ORDER BY, SET or VALUES list ends the line, so each column is on its own line and adding or removing one is a one-line change in version control.

Joins and conditions get their own lines. LEFT JOIN, INNER JOIN and the rest start a line under FROM, with their ON condition beside them. In WHERE and HAVING, each AND and OR starts a line, so every condition can be read, commented out or reordered on its own. The AND inside BETWEEN … AND … is part of one condition and stays on its line.

Subqueries are indented inside their brackets. A bracket that holds a SELECT opens a new level: the subquery's clauses are indented one step, and the closing bracket returns to the outer level. Brackets that hold anything else, such as a function's arguments or an IN list, stay on one line.

CASE gets one line per branch. CASE starts the expression, each WHEN and the ELSE sit one step in, and END comes back to CASE's level.

Statements are separated by a blank line.

Reading the example

The page opens with a report query written on one line, 433 characters long: customers in two cities, their orders over six months, a spending tier, excluding customers with refunds. Formatted, it becomes 32 lines. Here is the middle of it:

FROM
  customers c
  LEFT JOIN orders o ON o.customer_id = c.id
WHERE
  o.order_date BETWEEN '2026-04-01' AND '2026-09-30'
  AND c.city IN ('Pune', 'Jaipur')
  AND c.id NOT IN (
    SELECT
      customer_id
    FROM
      refunds
    WHERE
      amount > 0
  )

At a glance you can see that there is one join, three conditions, and that the third condition is a subquery with its own WHERE. On one line, finding that took reading every word.

Why the meaning cannot change

A formatter that changed a query's meaning would be worse than none. This one is built so that it cannot.

It splits the query into tokens first: words, numbers, 'strings', "quoted names", operators, brackets, commas and comments. Strings and quoted names are taken whole, so a comma, a keyword or a semicolon inside 'Mehta, Rahul' or "Order Date" is never mistaken for SQL.

It then writes the same tokens back in the same order, changing only the spaces between them and, if you ask, the letter case of keywords. Keywords are case-insensitive in every major database, so SELECT, select and Select mean the same.

The test checks it. For each sample query and each keyword-case setting, the test formats the query, splits both the original and the result into tokens, and checks that the two lists match. It also formats the result a second time and checks nothing moves, so formatting is stable.

Database differences it handles

The formatter is not tied to one database. It understands the quoting and symbols each one uses:

SyntaxUsed byExample
Backtick namesMySQL, MariaDB`order`
Bracket namesSQL Server[Order Details]
Double-quoted namesPostgreSQL, Oracle, SQLite"Order Date"
Casts with ::PostgreSQLcreated_at::date
ParametersPostgreSQL, Oracle, apps$1, :start, %s
Dollar-quoted bodiesPostgreSQL functions$$ … $$
N'…' and E'…' stringsSQL Server, PostgreSQLN'नमस्ते'
JSON operatorsPostgreSQLdata->>'name', tags @> '{a}'

Because it formats by layout rules rather than checking the query against one database's grammar, it also formats a query that has a mistake in it, which is often exactly when you want to read it.

Keyword case

UPPER-case keywords are the long-standing convention: they make the structure stand out from table and column names. Some teams prefer lower case. Either way, only words the formatter knows to be keywords change.

Words that are often names are left alone. date, name, key, type, text, status, year and user are keywords in some databases and column names in many tables. On MySQL running on Linux, table names are case-sensitive, so turning a table called user into USER could break a query. The formatter therefore never changes the case of those words, or of any word after a dot, such as t.select. Choose As typed to change no case at all.

Comments

Comments are kept when formatting, word for word. A -- comment at the end of a line stays at the end of that line, and the formatter always starts a new line after it, because everything after -- on the same line would otherwise become part of the comment. A /* … */ comment that started on its own line stays on its own line; one written in the middle of a line stays in place between the words around it.

This matters for queries pasted from code reviews and migration files, where the comments explain why a condition is there. Formatting a query should never be the reason that explanation disappears.

When to minify

Minify does the opposite: every statement on one line, single spaces, comments removed. It is useful for putting a query into application code, a log line, a JSON config or a spreadsheet cell. Comments are removed because a comment starting with -- runs to the end of the line, and on a one-line query it would hide everything after it. The example query, formatted and then minified, comes back as one 433-character line, the same length as the original, now with its keywords in capitals.

Large scripts

The formatter runs in your browser. In our test on a laptop, a script of 2,000 copies of the example query, 868 KB of SQL, was formatted in about 0.4 seconds. Database dumps of many megabytes work too; the result box shows the start of a very long result, and Copy and Download carry all of it.

To compare two versions of a query after formatting both, paste them into Text Compare: formatted SQL diffs line by line, so the change stands out.

What this tool assumes

  • The query is split into words, numbers, strings, quoted names, operators, brackets, commas, semicolons and comments; strings, quoted names, $$ bodies and comments are kept exactly.
  • Clause keywords start lines; their contents are indented; lists go one item per line; joins, AND and OR start lines; subqueries and CASE are indented.
  • Only whitespace and the case of known keywords change; words often used as names and words after a dot are never re-cased.
  • Minify removes comments and puts each statement on one line.
  • The SQL stays in your browser tab and is not uploaded.

Sources

Frequently asked questions

How do I format a SQL query?

Paste the query. The formatted version appears on the right at once, with each clause such as SELECT, FROM and WHERE on its own line, one column per line, and joins and conditions each on a new line. Copy it or download it as a .sql file.

Does formatting change what my query does?

No. Only the spaces and line breaks between words change, and the case of keywords if you choose UPPER or lower. Strings, quoted names, numbers and comments are kept exactly. Our test formats each sample, splits both versions into words and checks they match.

Which databases does it work with?

MySQL, PostgreSQL, SQL Server, SQLite, Oracle and others: it handles 'strings', "quoted" and `backtick` names, [bracketed] names, :: casts, $1 and :name parameters and $$ function bodies. It formats by layout rules rather than checking the SQL against one database, so it also formats a query that has a mistake in it.

What does minify do?

It puts each statement on one line with single spaces, which is handy for code, logs and config files. Comments are dropped, because a comment starting with -- would hide the rest of a one-line query.

Why are some words not made upper case?

Words that are often used as column or table names, such as date, name, key, type and text, are left as you typed them, because on some databases a table name's case matters. Choose As typed to change no case at all.

Is my SQL uploaded?

No. The query is formatted in this browser tab and nothing is sent anywhere, so it is safe for queries that contain table names or data from work.