SQL Formatter
100% LocalBeautify and format SQL queries for multiple dialects.
Query Optimization
Formats keywords to uppercase and applies consistent indentation for better readability and debugging.
Paste SQL to reformat with consistent indentation, keyword casing, and line breaks.
Learn More
Debugging Hallucinated SQL: A Developer’s Guide to Database Sanity
Postgres JSONB Patterns: When to Use NoSQL in Your SQL DB
Learn how to use Postgres JSONB for flexible, high-performance data storage. Master indexing, querying, and the common pitfalls of mixing SQL and NoSQL.
SQL vs. NoSQL in 2024: Why the Best Database is Both
What is SQL Formatter?
Frequently Asked Questions
Technical Deep Dive
SQL Formatter
Turn messy SQL queries into readable, well-structured statements. Supports MySQL, PostgreSQL, SQL Server, and generic SQL. Provides options for keywords casing and indentation.
sqlfluff enforces dialect rules in CI. This formatter is for a query you just pulled from logs and need to read, without uploading the table names.
Paste a single-line SELECT u.id,o.total FROM users u JOIN orders o ON o.user_id=u.id WHERE o.total>100. You should get clauses on their own lines.
Postgres ILIKE and SQL Server TOP are dialect-specific. Wrong dialect makes reserved-word highlighting lie.
01 Dialect Compatibility
| Database | Identifier Quote | Unique Features Supported |
|---|---|---|
| PostgreSQL | "double quotes" | :: cast, JSONB operators |
| MySQL | `backticks` | Index hints, STRAIGHT_JOIN |
| BigQuery | `backticks` | STRUCT, UNNEST, Project IDs |
| T-SQL | [brackets] | Table variables, CROSS APPLY |
02 Formatting Principles
-
Vertical Rhythm CTEs at the top, followed by the main SELECT. Each column on its own line to make Git diffs readable.
-
Keyword Casing Standardize on
UPPERCASEfor traditional readability orlowercasefor modern dbt-style conventions. -
Operator Alignment Boolean
AND/ORplaced at the start of new lines for logical clarity and easier debugging.
03 Why You're Pasting a Query In Here
Most of the SQL you'll format isn't yours, it's an ORM dump, a 200-line analytics view someone shipped years ago, or an EXPLAIN that needs to fit on one screen.
-
Code-reviewing a 200-line analytics query Half the comments on a SQL PR are about formatting. Run it through the formatter once and the discussion shifts to actual semantics, join correctness, NULL handling, window-function partitions.
-
Inspecting ORM-generated SQL Hibernate, SQLAlchemy, and ActiveRecord all emit single-line SQL with verbose alias names. Formatting reveals the N+1 in your
includeschain or the eager-load that fanned out into 12 joins. -
Debugging
EXPLAINplans A formatted query lines up visually with the plan's join order, easier to see which subquery became the costlySeq Scanon a 50M-row table. -
Normalizing query history for similarity
pg_stat_statementsalready normalizes; for raw slow-log dumps, formatting first makes it easier to group "same query, different literals" by visual diff. -
Preparing snippets for docs & tickets A formatted query in a bug report saves the reviewer 30 seconds of mental parsing. Trivial, and the kind of trivial that compounds across a team.
04 Worked Examples
SELECT
u.id,
u.email,
u.created_at,
COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
GROUP BY u.id, u.email, u.created_at;
SELECT
u.id
, u.email
, u.created_at
, COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
GROUP BY u.id, u.email, u.created_at;Comma-leading lets you toggle a column on/off by commenting one line, no fiddly trailing-comma surgery. Pick a style and enforce it in the formatter; rotating between the two in one repo is the worst of both worlds.
FROM orders o
INNER JOIN customers c ON c.id = o.customer_id
LEFT JOIN refunds r ON r.order_id = o.id AND r.status = 'completed'
LEFT JOIN payments p ON p.order_id = o.id AND p.captured_at IS NOT NULLFROM orders o
INNER JOIN customers c ON c.id = o.customer_id
LEFT JOIN refunds r ON r.order_id = o.id
AND r.status = 'completed'
LEFT JOIN payments p ON p.order_id = o.id
AND p.captured_at IS NOT NULLAligned style takes more horizontal space but makes a 6-way join readable at a glance. Use it for views that need to live in a repo for years; the default style is fine for ad-hoc queries.
WITH active_users AS (
SELECT id, email FROM users WHERE deleted_at IS NULL
),
recent_orders AS (
SELECT
o.id,
o.user_id,
o.total
FROM orders o
WHERE o.created_at >= NOW() - INTERVAL '30 days'
),
summary AS (
SELECT
au.id,
au.email,
SUM(ro.total) AS spend_30d
FROM active_users au
LEFT JOIN recent_orders ro ON ro.user_id = au.id
GROUP BY au.id, au.email
)
SELECT * FROM summary WHERE spend_30d > 100;Postgres : "user" -- double quotes for identifiers
MySQL : `user` -- backticks
Snowflake: "USER" -- double quotes; case-folds UPPER by default
SQL Server: [user] -- square brackets (also "user")A formatter that rewrites `user` to "user" will silently break a MySQL query when fed to a Postgres-aware tool. Always tell the formatter which dialect you're working in, or paste the dialect-specific output back to verify quoting survived.
05 Related Tools
Formatting is step one of any SQL workflow. These tools cover the steps that come next.
SQL Query Explainer
Once it's readable, get a plain-English breakdown of what each clause does, useful when reviewing a junior's query or onboarding to a new schema.
SQL Builder
When the formatted query is the wrong shape entirely, rebuild it from clauses rather than untangling 200 lines by hand.
Regex Tester
For the moment when LIKE isn't enough and you need to validate the ~ '^[a-z0-9]+$' Postgres regex you're about to paste into a CHECK constraint.