SQL Formatter

Format SQL for reading, or minify it, in the dialect you use.

Result
SELECT
  u.id,
  u.email,
  count(o.id) AS orders
FROM
  users u
  LEFT JOIN orders o ON o.user_id = u.id
WHERE
  u.created_at > '2026-01-01'
GROUP BY
  u.id,
  u.email
ORDER BY
  orders DESC

Runs in your browser. Nothing you enter is sent anywhere.

How to use it

Paste one or more statements into the SQL box. The result updates as you type, in your browser, so nothing is uploaded.

  1. Pick the Dialect your database speaks: PostgreSQL, MySQL, SQLite, BigQuery, SQL Server (T-SQL) or Standard SQL. It decides which quotes, comments and operators the parser accepts.
  2. Choose Format to lay the query out one clause and one column per line, or Minify to put it on as few lines as it allows.
  3. Set the keyword case: UPPER, lower or Preserve. With Format, pick 2 spaces or 4 spaces of indent.
  4. Press Copy next to Result.

If the parser can’t read the SQL, you get one sentence with the token it stopped at and its line and column.

Examples

A one-line query, with PostgreSQL, Format, UPPER and 2 spaces:

select u.email, count(*) as orders, case when sum(o.total) > 1000 then 'gold' else 'standard' end as tier from users u join orders o on o.user_id = u.id where o.status = 'paid' group by u.email
SELECT
  u.email,
  count(*) AS orders,
  CASE
    WHEN sum(o.total) > 1000 THEN 'gold'
    ELSE 'standard'
  END AS tier
FROM
  users u
  JOIN orders o ON o.user_id = u.id
WHERE
  o.status = 'paid'
GROUP BY
  u.email

Keywords are uppercased; count and sum keep the case they were typed in.

A MySQL query with backtick identifiers and a # comment, with MySQL:

select `order`, `user id` from `orders` # recent only
where created_at > now() - interval 7 day
SELECT
  `order`,
  `user id`
FROM
  `orders` # recent only
WHERE
  created_at > now() - INTERVAL 7 DAY

The same text with PostgreSQL fails at the first backtick, because PostgreSQL quotes identifiers with double quotes:

Unexpected "`order`, `" at line 1, column 8.

A commented query, with Minify:

-- active users only
select id,   email
from users
where active = true   /* soft-deleted rows stay */
  and name = 'Ada  Lovelace';
-- active users only
SELECT id, email FROM users WHERE active = TRUE /* soft-deleted rows stay */ AND name = 'Ada  Lovelace';

A -- comment runs to the end of its line, so the line break after it stays; otherwise the next token would be commented out. The two spaces inside the string are data and stay too.

A missing parenthesis:

select * from users where id in (1, 2, 3

The error is Unexpected end of input at line 1, column 41. The parser reached the end still waiting for ).

Good to know

  • The dialect changes what parses. Identifiers are quoted with "…" in PostgreSQL and standard SQL, with backticks in MySQL and BigQuery, and with […] in SQL Server; SQLite accepts all three. MySQL and BigQuery allow # comments, and PostgreSQL has :: casts and $$…$$ bodies. A valid query in the wrong dialect can fail.
  • Only layout and keyword case change. Strings, quoted identifiers, comments and dollar-quoted function bodies are copied as written; nothing inside a $$ body is reformatted. Function names such as now(), data types such as varchar(255), and table and column names keep your case. UPPER and lower apply to keywords like SELECT, AS, TRUE and CURRENT_DATE.
  • Keyword case doesn’t change what a query does. SQL keywords are case-insensitive in every major database. Uppercase keywords are a readability convention.
  • Minify collapses layout, not syntax. Every run of whitespace between tokens becomes one space, so a = b keeps its spaces, and comments are kept. Statements stay separated by ;.
  • It’s a formatter, not a validator. It doesn’t know your schema, and some broken SQL still lays out: select * users where comes back on three lines, with no error. Run the query to know it’s valid.
  • Placeholders work in their own dialect: $1, :id and psql’s :'name' in PostgreSQL, ? in MySQL, @id in SQL Server. A colon after a name, as in the slice arr[lo:hi], is left as it is.
  • Templated SQL fails. dbt and Jinja syntax such as {{ ref('orders') }} isn’t SQL until it’s rendered, so it stops at the {{.
  • Input is limited to 200,000 characters. The result block shows the first 20,000 characters; Copy copies all of it. The formatting is done by the open-source sql-formatter library, version 15.4.0.

Questions

How do I format a SQL query?

Paste it into the SQL box, pick your database’s Dialect and copy the Result. Each clause such as SELECT, FROM and WHERE starts a line, the columns and conditions under it are indented, and joins sit inside the FROM block.

Should SQL keywords be uppercase?

Not for the database: select and SELECT run the same everywhere. Uppercase keywords are a common style because they separate the language from your table and column names; many teams pick one case and let a formatter enforce it.

How do I format SQL from the command line?

The library this page uses has a CLI: npx sql-formatter -l postgresql query.sql prints the formatted query, and --fix rewrites the file in place. For PostgreSQL there’s also pg_format, and SQLFluff can format as well as lint.

Why won’t my SQL format?

Usually the dialect is wrong, a quote or parenthesis isn’t closed, or the text holds template syntax. The error names the token and the line and column where the parser stopped, so look there first.