What is SQL formatting and why does it matter?
SQL formatting (or beautifying) is the practice of applying consistent indentation, line breaks, and casing to SQL queries so they are easier to read, review, and debug. While the SQL standard (ISO/IEC 9075) doesn't mandate any particular layout — engines accept the same query as a single line or 50 — there are decades of community conventions that make code review faster, bug-spotting easier, and onboarding cheaper.
A well-formatted query communicates structure at a glance: the SELECT list, the FROM chain of joins, the WHERE predicates, the GROUP BY dimensions, the HAVING filters, and the ORDER BY sort. Compare these two equivalent queries:
SELECT u.id, u.email, count(o.id) AS orders, sum(o.total) AS revenue FROM users u LEFT JOIN orders o ON o.user_id=u.id WHERE u.created_at >'2026-01-01' AND u.deleted_at IS NULL GROUP BY u.id, u.email HAVING count(o.id)>0 ORDER BY revenue DESC LIMIT 100;
SELECT
u.id,
u.email,
COUNT(o.id) AS orders,
SUM(o.total) AS revenue
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE u.created_at > '2026-01-01'
AND u.deleted_at IS NULL
GROUP BY u.id, u.email
HAVING COUNT(o.id) > 0
ORDER BY revenue DESC
LIMIT 100;
The formatted version has the same logic and identical execution plan, but pull-request reviewers can scan the join chain and the filters in seconds. When something breaks in production, the on-call engineer can read the query in their phone's kubectl logs output without unpacking 200 chars of compressed text.
How SQL formatters work under the hood
A SQL formatter is a small compiler. The pipeline has three stages:
- 1. Lexer / tokenizer. Splits the input into tokens — keywords (
SELECT,FROM), identifiers (users,u), operators (=,>), literals ('2026-01-01',100), comments, and whitespace. The tokenizer needs to know the dialect to recognize keywords correctly —LIMITis a keyword in MySQL/Postgres but a function in SQL Server (TOPinstead). - 2. Parser. Builds an Abstract Syntax Tree (AST) from the token stream, recognizing the structure:
SELECTlists,FROMchains with joins, predicates, subqueries, CTEs, and so on. A robust parser handles dialect quirks like PostgresRETURNING, SQL ServerOUTPUT, MySQLON DUPLICATE KEY. - 3. Pretty-printer. Walks the AST and emits formatted SQL with the chosen indent width, comma style, keyword case, and line-break rules. This step decides whether
JOINkeywords align withFROM, whether commas go before or after fields, whether short queries stay on one line, and so on.
This tool uses a battle-tested SQL parser (the same approach as sql-formatter on npm and PgFormatter) and runs all three stages in your browser. No query ever leaves your machine — important when you're formatting queries that touch real customer data, contain hard-coded credentials, or expose schema names you'd rather not share.
SQL dialect differences — what to know
"SQL" isn't one language. The 1992 ANSI SQL standard is the common ancestor, but every major engine has added features (and quirks) over decades. The five dialects this formatter handles cover >95% of real-world SQL.
| Feature | MySQL | PostgreSQL | SQL Server | Oracle | SQLite |
|---|---|---|---|---|---|
| Limit syntax | LIMIT n | LIMIT n | SELECT TOP n / OFFSET FETCH | FETCH FIRST n ROWS | LIMIT n |
| String concat | CONCAT() only | || or CONCAT() | + or CONCAT() | || | || |
| Identifier quoting | Backticks `tbl` | Double quotes "tbl" | Brackets [tbl] or quotes | Double quotes | Backticks or quotes |
| Case-sensitivity (unquoted) | Database-config dependent | Folded to lowercase | Insensitive by default | Folded to UPPERCASE | Insensitive |
| Auto-increment | AUTO_INCREMENT | SERIAL / IDENTITY | IDENTITY(1,1) | Sequences + triggers | AUTOINCREMENT |
| Boolean type | TINYINT(1) | BOOLEAN | BIT | No native — use NUMBER(1) | INTEGER |
| Insert + return | Two queries | INSERT ... RETURNING | OUTPUT INSERTED.* | RETURNING ... INTO | RETURNING (3.35+) |
| Common Table Exprs (CTEs) | 8.0+ | Yes | Yes | Yes | 3.8+ |
| Window functions | 8.0+ | Yes | Yes | Yes | 3.25+ |
| JSON support | Yes (5.7+) | JSONB (best) | Yes (2016+) | JSON_TABLE | JSON1 |
Pick the right dialect in the formatter dropdown — it changes how reserved words are recognized, how strings are quoted, and how identifiers are escaped. Formatting Postgres SQL with the MySQL setting can incorrectly uppercase or quote things.
Formatting style choices — pick once, apply everywhere
Even with a fixed dialect, formatters expose dozens of style toggles. The four that matter most:
1. Keyword case
- UPPERCASE (most common in dbt, traditional enterprise) — keywords stand out from identifiers, easy to spot in dense code review.
- lowercase (modern style, popular in startups, used by SQLFluff defaults) — looks cleaner, modern editors highlight keywords with color anyway.
- Preserve — leave the original case. Useful when reformatting legacy code without imposing a style.
2. Indent width
4 spaces is the historical default. Modern teams often use 2 spaces to fit deeply-nested CTEs in a single screen. Tabs are rare in SQL but valid. Pick one site-wide; mixing is a code-review red flag.
3. Comma placement
- Trailing comma (after the field):
SELECT a, b, c— most common. Easy to type. Diff-noisy when adding fields (because the last line changes). - Leading comma (before the field):
SELECT a— diff-friendly but visually unusual outside data-warehouse teams.
, b
, c
4. JOIN style
Modern SQL strongly prefers explicit JOIN with ON conditions over the legacy comma-and-WHERE style. Implicit joins are still valid but easy to miss when scanning, and join conditions get tangled with filter conditions.
.sqlfluff or sql-formatter.config.json to your repo. Pin every style choice. Run formatting in CI. The PR comments about indentation will stop forever.
SQL formatting in 8 toolchains
npm: sql-formatter
import { format } from 'sql-formatter';
const formatted = format(rawSQL, {
language: 'postgresql', // mysql | postgresql | tsql | plsql | sqlite | bigquery
keywordCase: 'upper',
tabWidth: 4,
useTabs: false,
linesBetweenQueries: 2,
});
Python: sqlparse
import sqlparse
formatted = sqlparse.format(
raw_sql,
reindent=True,
keyword_case='upper',
indent_width=4,
)
Python: SQLFluff (linter + formatter)
# Lint
sqlfluff lint queries/ --dialect postgres
# Auto-fix style violations
sqlfluff fix queries/ --dialect postgres
# Format only (no linting)
sqlfluff format query.sql --dialect postgres
VS Code: SQL formatters
// Top extensions:
// - "SQL Formatter" (adpyke) — uses sql-formatter under the hood
// - "SQLFluff" — for dbt projects
// - "Prettier SQL VSCode" — Prettier-style formatting
// Keybind format-on-save in settings.json:
{
"editor.formatOnSave": true,
"[sql]": { "editor.defaultFormatter": "adpyke.vscode-sql-formatter" }
}
JetBrains DataGrip / IntelliJ
// Built-in formatter: Code → Reformat Code (Ctrl+Alt+L / Cmd+Opt+L)
// Settings → Editor → Code Style → SQL → [Dialect]
// Per-dialect rules. Sync via "Settings Repository" or .editorconfig
PostgreSQL: pg_format / PgFormatter
# Install
brew install pgformatter # macOS
sudo apt install pgformatter # Debian/Ubuntu
# Format a file
pg_format -s 4 -u 1 query.sql > query.formatted.sql
# Pipe input
echo "select * from users where id=1;" | pg_format
dbt: built-in formatting
# dbt uses SQLFluff under the hood
# In your dbt project root, add .sqlfluff config:
[sqlfluff]
dialect = snowflake
templater = dbt
exclude_rules = L032
# Then run:
sqlfluff fix models/
Bash one-liner via Docker
# If you don't want to install anything:
docker run --rm -i sqlfluff/sqlfluff:latest format - --dialect postgres < query.sql
# Or use Prettier with @prettier/plugin-sql
npx prettier --plugin=prettier-plugin-sql --parser=postgresql query.sql
Common SQL anti-patterns the formatter exposes
Beautified SQL doesn't just look nice — it makes anti-patterns easier to spot. Here are the most common ones:
| Anti-pattern | Why it's bad | Better |
|---|---|---|
SELECT * in production |
Breaks when columns added; sends unused data; obscures dependencies | Enumerate columns explicitly |
Implicit joins (FROM a, b WHERE) |
Easy to miss the join condition; mixing with explicit joins is a mess | Explicit JOIN ... ON |
| Subqueries instead of CTEs | Hard to read deeply nested; can't reuse the same subquery twice | Use WITH cte AS (...) CTEs (modern SQL) |
Cartesian product from missing ON |
Returns rows×rows; massive result sets, slow queries | Always provide a join condition; review join chains carefully |
Functions on indexed columns in WHERE |
WHERE LOWER(email) = 'x' can't use the index on email |
Use case-insensitive collation, or a functional index |
OFFSET for pagination at scale |
O(N) — Postgres has to scan and skip rows. Slow past page 100 | Cursor pagination using WHERE id > last_seen_id |
NOT IN with NULL values |
Returns nothing — three-valued logic gotcha | NOT EXISTS or LEFT JOIN ... WHERE x IS NULL |
Best SQL formatter for 2026 — what to compare
Search results for "sql formatter online", "sql beautifier", "format sql query" return many tools but most ignore dialect (PostgreSQL RETURNING, MySQL LIMIT, SQL Server TOP all parsed differently). Three things separate the good from the noise: dialect awareness (correct keyword recognition for MySQL vs Postgres vs SQL Server), style configurability (keyword case, indent width, comma placement, JOIN style), and whether queries are processed locally or uploaded to a server. Here is how the most-used SQL formatters compare in 2026:
| Tool | Dialects | Style options | Browser-only | Bulk & CLI | Cost |
|---|---|---|---|---|---|
| FreeDevTool SQL Formatter | MySQL + PG + MSSQL + Oracle + SQLite | Case + indent + JOIN style | Yes | No | Free |
| sqlformat.org | Generic SQL | Limited | Server-side | API available | Free, ad-funded |
| poorsql.com | SQL Server biased | Style template | Server-side | Yes (paid) | Freemium |
npm sql-formatter | 14+ dialects (PG, MySQL, MSSQL, BigQuery, Snowflake, etc.) | Full config | Local install | Yes (CLI) | Free, OSS |
| SQLFluff (Python) | 15+ dialects, including dbt + Spark | Linter + formatter | Local install | Yes (CLI + CI) | Free, OSS |
| JetBrains DataGrip | All major dialects | Comprehensive | Local IDE | Yes (IDE) | Paid (~$199/yr) |
How do I format SQL queries online without uploading them to a server?
Paste any SQL into the input pane on this page. Formatting runs entirely in the browser via a JS implementation of the npm sql-formatter grammar — no upload, no server fetch. This matters because production queries often contain table names, column names, or hard-coded values (test data, customer IDs) that you don't want logged. Avoid online formatters that POST to a server endpoint (check DevTools Network tab on first format) — common pattern with sqlformat.org, poorsql.com, and most ad-funded "free SQL formatter" sites.
What are the differences between MySQL, PostgreSQL, and SQL Server syntax?
The 2026 dialect divergence has narrowed but still bites in formatting:
| Feature | MySQL 8.4 | PostgreSQL 18 | SQL Server 2025 |
|---|---|---|---|
| Limit results | LIMIT 10 | LIMIT 10 or FETCH FIRST 10 ROWS | TOP 10 or OFFSET ... FETCH NEXT |
| String concat | CONCAT(a, b) | a || b or CONCAT() | a + b or CONCAT() |
| Auto-increment | AUTO_INCREMENT | SERIAL / GENERATED AS IDENTITY | IDENTITY(1,1) |
| Insert returning | None (use last_insert_id()) | RETURNING * | OUTPUT INSERTED.* |
| UPSERT | INSERT ... ON DUPLICATE KEY UPDATE | INSERT ... ON CONFLICT DO UPDATE | MERGE |
| UUIDv7 native | Helper function (8.4+) | uuidv7() (PG 18 native) | NEWSEQUENTIALID() (similar) |
Pick the right dialect dropdown so the formatter recognizes RETURNING, TOP, MERGE, and other dialect-specific keywords as keywords (uppercased) rather than identifiers (left as-is).
SQL formatter alternative to sqlformat.org — 4 reasons developers switched
- Browser-only, no upload. sqlformat.org POSTs your query to a Python backend. Production queries with PII or unreleased schema names should never leave your browser.
- 5 dialects with proper keyword recognition. Most online formatters use a generic SQL grammar that misformats
RETURNING(PG),TOP(MSSQL), orMERGE(MSSQL/Oracle). This tool handles all five major dialects. - Style options visible upfront. Keyword case, indent width, JOIN-on-newline are sliders/toggles at the top — not hidden behind a config file or "Settings" page.
- No ads, no rate limit. Free SQL formatters indexed by Google almost universally inject ads or cap requests per minute. This page has neither.
Pair the SQL formatter with the JSON Formatter for API responses and migrations as JSONB, the UUID Generator for UUIDv7 primary keys (PG 18 native), and the Generation & Formatting Tools hub for the broader formatter toolkit.
SQL formatter best practices
- Format on save in your editor. The diff between formatted and unformatted SQL should never appear in a PR. Set up
editor.formatOnSavefor SQL files. - Pin a config file. Commit
.sqlfluff,.sql-formatter, or your IDE settings to the repo. Don't rely on each developer's local preferences. - Run formatting in CI. Block PRs that don't match the agreed style.
sqlfluff lint --dialect postgresis the easiest gate. - Don't format auto-generated SQL. ORM-emitted queries (Hibernate, ActiveRecord, Sequelize) live in your logs, not your repo. Reformatting them just adds review noise.
- Format BEFORE committing. Reformatting committed code creates noisy diffs that bury real changes. Set up a pre-commit hook.
- Use
git blame-friendly mode in massive reformats. Use.git-blame-ignore-revsto mark "format-only" commits so blame still shows real authors. - Format inside string literals carefully. SQL embedded in JS/Python/Go strings often shouldn't be reformatted — multi-line raw strings preserve indentation. Most formatters skip these correctly; verify.