# How I built a dialect-aware SQL formatter that runs in your browser

> I built a browser-based SQL formatter that supports multiple database dialects, configurable indentation, keyword casing, comma styles and line wrapping. The SQL never leaves your browser.

Author: Nimoy Burrowes (https://nimoyburrowes.com/about)
Category: Tools
Published: 2026-08-01T05:00:00.000Z
Updated: 2026-08-06T00:26:20.848Z
Canonical: https://nimoyburrowes.com/blog/dialect-aware-sql-formatter-runs-in-browser

---

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_amountFROM  clients c  INNER JOIN transactions t ON t.client_id = c.client_idWHERE  t.status = 'COMPLETED'  AND t.transaction_date >= '2026-01-01'GROUP BY  c.client_id,  c.nameHAVING  SUM(t.amount) > 100000ORDER 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  customersLIMIT  10;

```

Identifier quoting also varies:

```sql

-- SQL ServerSELECT  [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_idFROM  customers;

```

Others use lowercase:

```sql

select  customer_idfrom  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_addressFROM  customers;

```

Leading commas place it at the beginning of the next line:

```sql

SELECT    customer_id  , customer_name  , email_addressFROM  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" = $1ORDER 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,  statusFROM  customersWHERE  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.

## Frequently asked questions

### Is the SQL sent to a server?

No. Formatting runs through a JavaScript library inside the browser. The query is not submitted to a backend for processing or storage.

### Which SQL dialect should I select?

Select the database engine that will execute the query. This helps the formatter understand engine-specific identifier quoting, keywords, functions and operators. Standard SQL is a reasonable fallback for generic queries.

### Does formatting a query change what it does?

Formatting is intended to change whitespace, indentation and casing rather than query behaviour. You should still review the output before executing it, particularly when working with unusual syntax or complex scripts.

### Can it validate my SQL?

No. The formatter does not connect to your database and cannot verify table names, columns, permissions, data types or business logic. It formats the query but does not prove that the query is valid or safe.

### Can it format SQL generated by an ORM?

Yes. Formatting SQL copied from ORM logs is one of its most useful applications. It can make generated joins, aliases, filters and selected columns much easier to inspect.

### Does it support CTEs and window functions?

Yes. Common table expressions and window functions are supported, along with many modern dialect-specific operators. Selecting the appropriate SQL dialect produces the best result.

### Does it support stored procedures?

The underlying formatting library does not fully support stored procedures. Individual SQL statements may format correctly, but complete procedural blocks can contain syntax the formatter cannot parse.

### Is it a replacement for the formatter in my IDE?

Not necessarily. An IDE-integrated formatter is more convenient during normal development. The browser tool is useful when SQL comes from a log, message, monitoring platform or machine where your normal development tools are unavailable.
