A significant amount of the SQL I review does not begin inside a clean `.sql` file.
It comes from application logs, ORM output, monitoring tools, production troubleshooting sessions, another developer and database traces. The query may be technically valid, but it often arrives as one long line:
```sql
select c.client_id,c.name,sum(t.amount) total_amount from clients c inner join transactions t on t.client_id=c.client_id where t.status='COMPLETED' and t.transaction_date>='2026-01-01' group by c.client_id,c.name having sum(t.amount)>100000 order by total_amount desc;
```
That is manageable when the query is small. Once it contains several joins, nested conditions, common table expressions, window functions or hundreds of selected columns, reading it becomes unnecessarily difficult.
So I built an online SQL formatter.
It supports multiple SQL dialects, runs entirely in the browser and provides enough formatting controls to match the conventions used by different developers and database teams. There is no signup, no SQL upload and no server-side formatting process.
Formatting SQL is not only about appearance
It is easy to describe SQL formatting as making code look better. That undersells its value. Good formatting exposes the structure of a query. After formatting the earlier example, the logical sections become much easier to identify:
```sql
SELECT
c.client_id,
c.name,
SUM(t.amount) AS total_amount
FROM
clients c
INNER JOIN transactions t ON t.client_id = c.client_id
WHERE
t.status = 'COMPLETED'
AND t.transaction_date >= '2026-01-01'
GROUP BY
c.client_id,
c.name
HAVING
SUM(t.amount) > 100000
ORDER BY
total_amount DESC;
```
The formatted query is not inherently more correct than the original. The database will generally interpret both versions in the same way.
The difference is how quickly a human can reason about them.
The join condition is visible. The filters are separated. The grouping columns can be compared with the non-aggregated columns in the `SELECT` list. The `HAVING` condition is clearly distinguished from the `WHERE` condition. Formatting reduces the amount of mental work required before the actual review can begin.
That matters when investigating production problems. A missing condition, an accidental cross join or an incorrectly grouped expression can have a much larger impact than a formatting mistake. Consistent formatting helps those problems become visible earlier.
Why SQL dialect selection matters
SQL has a common foundation, but there is no single implementation used by every database engine.
For example, SQL Server supports constructs such as:
```sql
SELECT TOP 10
*
FROM
dbo.customers;
```
PostgreSQL and MySQL would more commonly use:
```sql
SELECT
*
FROM
customers
LIMIT
10;
```
Identifier quoting also varies:
```sql
-- SQL Server
SELECT
[order]
FROM
[transaction];
-- MySQL
SELECT
`order`
FROM
`transaction`;
-- PostgreSQL
SELECT
"order"
FROM
"transaction";
```
Database-specific functions, operators, reserved words and procedural syntax create additional differences. That is why the formatter asks for a dialect instead of treating all SQL as generic text. The selected dialect helps the formatting library interpret the query using the rules of the intended database engine.
The tool currently exposes support for 14 engines, including PostgreSQL, MySQL, MariaDB, SQLite, SQL Server, BigQuery, Snowflake and Redshift. A generic Standard SQL option is also available when the target engine is unknown. Choosing the correct dialect becomes especially important when a query uses engine-specific syntax. The underlying `sql-formatter` library accepts a language configuration and can return parsing errors when syntax from one engine is interpreted using another engine's rules.
What happens inside the browser
The main design requirement was straightforward:
The SQL should not need to leave the browser to be formatted.
The tool uses the open-source JavaScript `sql-formatter` library. Once the page and its JavaScript have loaded, the formatting operation takes place inside the browser tab. The SQL is passed directly to the local formatting function rather than posted to an application server.
Conceptually, the operation looks like this:
```javascript
import { format } from 'sql-formatter';
const formattedSql = format(inputSql, {
language: 'transactsql',
tabWidth: 2,
keywordCase: 'upper',
linesBetweenQueries: 1,
expressionWidth: 80
});
```
The options selected in the interface are translated into formatter configuration values. When an option changes, the query can be formatted again locally without a database connection.
No database credentials are required because the tool does not connect to a database. It does not need access to table definitions, indexes, query plans or production systems.
You can verify the local behaviour yourself:
1. Open the browser's developer tools.
2. Select the Network panel.
3. Clear the existing network activity.
4. Paste SQL into the formatter.
5. Change the formatting options.
The SQL is reformatted without a request containing the query being sent to the server. The website may still load ordinary page resources and record page-view analytics, but the formatter's SQL input and output are not submitted for processing or logging.
The formatting options I included
Different teams have surprisingly strong opinions about SQL style.
Some use uppercase keywords:
```sql
SELECT
customer_id
FROM
customers;
```
Others use lowercase:
```sql
select
customer_id
from
customers;
```
Some database teams use two spaces for indentation. Others use four spaces, eight spaces or tabs. Comma placement is another common disagreement.
Trailing commas place the separator at the end of the previous line:
```sql
SELECT
customer_id,
customer_name,
email_address
FROM
customers;
```
Leading commas place it at the beginning of the next line:
```sql
SELECT
customer_id
, customer_name
, email_address
FROM
customers;
```
Leading commas are particularly useful when reviewing changes. Adding or removing a selected column is less likely to modify the previous line, which can produce a cleaner source-control diff. The formatter therefore includes controls for:
* SQL dialect
* Uppercase, lowercase or preserved keyword casing
* Two-space, four-space, eight-space or tab indentation
* Leading or trailing commas
* The number of lines between separate queries
* Expression wrapping width
The output can be copied, downloaded as a `.sql` file or moved back into the input panel for another formatting pass.
Why wrapping width is useful
Long expressions create a difficult formatting problem. Consider this condition:
```sql
WHERE COALESCE(account.current_balance, 0) + COALESCE(account.pending_balance, 0) - COALESCE(account.restricted_balance, 0) > 1000000
```
On a wide monitor, keeping the expression on one line may be readable. In a code-review panel, split-screen editor or narrow laptop window, it may require horizontal scrolling. The wrap-width setting tells the formatter how aggressively it should break longer expressions into multiple lines. A smaller width generally produces more line breaks:
```sql
WHERE
COALESCE(
account.current_balance,
0
) + COALESCE(
account.pending_balance,
0
) - COALESCE(
account.restricted_balance,
0
) > 1000000
```
A larger width keeps more expressions together. There is no universally correct value. The best setting depends on the team's style guide, screen sizes and where the SQL will normally be reviewed.
Formatting ORM-generated SQL
One of the most practical uses for the tool is reading SQL generated by an object-relational mapper. Libraries and frameworks such as Sequelize, Prisma, Hibernate, Django and ActiveRecord can produce queries that are valid but difficult to inspect in their logged form. A log entry may contain:
```sql
SELECT "User"."id","User"."email","Orders"."id" AS "Orders.id","Orders"."total" AS "Orders.total" FROM "users" AS "User" LEFT OUTER JOIN "orders" AS "Orders" ON "User"."id"="Orders"."user_id" WHERE "User"."status"=$1 ORDER BY "User"."created_at" DESC;
```
Formatting it makes the generated join structure and aliases easier to understand:
```sql
SELECT
"User"."id",
"User"."email",
"Orders"."id" AS "Orders.id",
"Orders"."total" AS "Orders.total"
FROM
"users" AS "User"
LEFT OUTER JOIN "orders" AS "Orders"
ON "User"."id" = "Orders"."user_id"
WHERE
"User"."status" = $1
ORDER BY
"User"."created_at" DESC;
```
This is helpful when investigating unexpected joins, duplicate rows, missing filters, inefficient eager loading or queries that return more data than the application needs. The formatter also handles common SQL features such as common table expressions, window functions and modern JSON operators.
Better formatting produces better diffs
Suppose a query is stored as one line:
```sql
select id,name,email,status from customers where status='ACTIVE';
```
Adding `created_at` can cause the source-control system to show the entire line as changed. With one item per line:
```sql
SELECT
id,
name,
email,
created_at,
status
FROM
customers
WHERE
status = 'ACTIVE';
```
The diff can show only the new column. That makes code review faster and reduces the chance that a meaningful change is hidden inside a large block of reformatted text. For that reason, teams should ideally format SQL before it is committed - not after several functional changes have already been combined with a complete formatting rewrite.
What the formatter does not do
A SQL formatter is not a SQL execution engine. It does not:
* Connect to your database
* Confirm that a table or column exists
* Check user permissions
* Estimate query cost
* Display an execution plan
* Detect every logical error
* Prove that a query is safe to run
* Optimize the query for a particular dataset
A query can be perfectly formatted and still be wrong. For example:
```sql
DELETE FROM
customer_transactions;
```
The formatter can make that statement easier to read. It cannot know whether deleting every row was the developer's intention. Similarly, it cannot determine whether a join will create duplicate records without knowing the table relationships and underlying data. Formatting should therefore be treated as one part of a SQL workflow. Validation, testing, query-plan analysis and peer review are still necessary.
The underlying library also documents limitations around stored procedures and custom statement delimiters. Complex procedural scripts may therefore require manual formatting or an editor designed specifically for that database platform.
Why I made it a web tool
Most database IDEs already have SQL formatting features. Editors such as VS Code also have extensions that can format SQL. Those are still the best options when you are working inside a configured development environment. The browser tool is for the gaps between those environments:
* Reviewing a query copied from a log
* Formatting SQL sent through a chat
* Working on a locked-down computer
* Inspecting ORM-generated SQL
* Cleaning a query before adding it to documentation
* Comparing formatting styles
* Quickly downloading a readable `.sql` file
* Formatting SQL without installing an extension
It is deliberately small and single-purpose. Paste the SQL, select the correct dialect, adjust the style and copy the result.
The formatter is available free in the Tools section of this site. It requires no account and the SQL remains in the browser tab.

