PostgreSQL SQL Formatter — Format Postgres Queries in Your Browser
Table of Contents
pgAdmin has a format SQL option buried in the keyboard shortcuts. It works for short queries but breaks on anything with JSONB operators (the @> and ->> syntax confuses it), recursive CTEs, or LATERAL joins. If you write Postgres for a living, you have probably given up on pgAdmin's formatter and switched to writing everything by hand.
Our formatter handles PostgreSQL syntax cleanly. Pick the PostgreSQL dialect, paste your query, and you get clean output that respects how Postgres works — JSONB operators stay intact, recursive CTEs format properly, and PL/pgSQL function bodies get nested indentation. No upload, no Postgres credentials, no signup.
Why pgAdmin Format SQL Falls Short for Real Postgres Queries
pgAdmin's format option is fine for SELECT * FROM users WHERE id = 1. The moment you use anything Postgres-specific, it gets confused:
- JSONB operators get mangled — the @>, ->, ->>, ?|, and ?& operators sometimes get spaces inserted in the wrong places, breaking the query.
- WITH RECURSIVE CTEs collapse — the recursive part loses its visual hierarchy, making the termination case hard to spot.
- LATERAL joins lose indentation — the LATERAL keyword and its subquery get crammed onto one line.
- FILTER clauses on aggregates — COUNT(*) FILTER (WHERE status = 'active') gets squished.
- PL/pgSQL function bodies — DECLARE, BEGIN, EXCEPTION blocks lose their nesting.
- Array operations — ANY(array), ALL(array), and array slicing get inconsistent spacing.
Our formatter fixes each of these. The PostgreSQL dialect knows about JSONB, recursive CTEs, LATERAL, FILTER, PL/pgSQL, and array operations.
PostgreSQL Syntax Our Formatter Handles Cleanly
The PostgreSQL dialect option enables special handling for Postgres-specific constructs. Here is what survives the trip through our formatter intact:
JSONB query operators — column @> '{"key": "value"}'::jsonb stays on one line. Long JSONB literals get wrapped at sensible points.
Recursive CTEs — WITH RECURSIVE category_tree AS (...) gets clear separation between the base case and the recursive UNION ALL part.
LATERAL joins — JOIN LATERAL (SELECT ...) AS sub ON true gets the LATERAL subquery indented as a proper block.
FILTER on aggregates — SUM(amount) FILTER (WHERE status = 'paid') stays on one line for short filters, breaks across lines for long ones.
RETURNING clauses — INSERT, UPDATE, and DELETE statements with RETURNING get the RETURNING clause on its own line, properly aligned.
UPSERT (ON CONFLICT) — ON CONFLICT (column) DO UPDATE SET formatted as a separate block under the INSERT statement.
Array operators — ANY(array), ALL(array), array['a','b','c'], and slice notation all get consistent spacing.
How to Format a PostgreSQL Query in Your Browser
- Copy your query from pgAdmin, DBeaver, psql, or wherever you write it — even from a Slack message if a teammate sent it.
- Paste it into the formatter input — handles queries up to about 500KB.
- Set dialect to PostgreSQL — this enables JSONB operator handling and recursive CTE formatting.
- Pick indent — 2 or 4 spaces — Postgres community style guides vary. Pick what your team uses.
- Toggle uppercase keywords — most Postgres style guides use uppercase keywords. Leave the toggle on.
- Click Format — output appears with syntax highlighting. Click Copy or download as a .sql file.
If you are putting the query in a migration file, save the formatted version directly to your migrations directory.
Sell Custom Apparel — We Handle Printing & Free ShippingReal-World Postgres Formatting Wins You Get From This Tool
Recursive CTE for hierarchical data. A category tree query with WITH RECURSIVE has a base case and a recursive case joined by UNION ALL. Our formatter visually separates them so you can spot termination conditions at a glance.
JSONB filtering. SELECT * FROM events WHERE properties @> '{"event_type": "purchase"}'::jsonb AND properties->>'amount' >= '100'. The operators stay intact, the query stays readable.
Window functions for time series. SELECT user_id, SUM(amount) OVER (PARTITION BY user_id ORDER BY created_at ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW). Each part of the OVER clause goes on its own line.
UPSERT with conflict resolution. INSERT INTO users (...) VALUES (...) ON CONFLICT (email) DO UPDATE SET name = EXCLUDED.name, updated_at = now(). The ON CONFLICT block is clearly separated from the INSERT.
PL/pgSQL function bodies. CREATE OR REPLACE FUNCTION with DECLARE, BEGIN, EXCEPTION, and END blocks gets proper nested indentation, making it possible to spot block-level bugs visually.
Postgres Formatter Comparison — Browser Tool vs Other Options
| Tool | Cost | Postgres Support | Privacy |
|---|---|---|---|
| Hawk SQL Formatter (this tool) | Free | Native PostgreSQL dialect, JSONB-aware | 100% browser, no upload |
| pgAdmin built-in format | Included | Basic, breaks on JSONB | Stays in pgAdmin |
| DBeaver SQL formatter | Free | Good but generic, not Postgres-aware | Local install |
| JetBrains DataGrip | $229/year | Strong with Postgres driver | Local install |
| pgFormatter (perl CLI) | Free, install required | Excellent, Postgres-specific | Local |
| VS Code + Prisma extension | Free | Good for schema files | Local |
For one-off formatting, the browser tool is fastest. For team-wide consistency, install pgFormatter on your CI server and run it on every PR — it is the most Postgres-aware tool available.
Other Browser Tools Postgres Developers Use Daily
Beyond formatting, these browser tools handle the most common Postgres workflow tasks:
JSON formatter — when you SELECT a JSONB column, the result is JSON. Our JSON formatter gives you a tree view to navigate it.
SQL diff checker — compare two versions of a query (before vs after refactor) using the SQL query diff tool.
Cron expression generator — pg_cron uses standard cron syntax. Generate the schedule visually instead of writing it from memory.
Regex tester — Postgres supports POSIX regex via the ~ operator. Test patterns in our regex tester before dropping them into a query.
Try It Free — No Signup Required
Runs 100% in your browser. No data is collected, stored, or sent anywhere.
Open Free SQL FormatterFrequently Asked Questions
Does this formatter understand JSONB operators like @> and ->>?
Yes. The PostgreSQL dialect setting recognizes all JSONB operators: @>, <@, ->, ->>, #>, #>>, ?, ?|, ?&, ||, -, and #-. They stay intact during formatting and do not get broken by stray whitespace.
Will the formatter execute or validate my query against my Postgres database?
No. This is a text-only formatter that runs in your browser. It does not connect to any database and your query never leaves your device. Safe for production queries with sensitive table names.
Can I format CREATE FUNCTION blocks with PL/pgSQL bodies?
Yes. CREATE OR REPLACE FUNCTION with DECLARE, BEGIN, EXCEPTION, and END blocks gets proper nested indentation. The function language (LANGUAGE plpgsql) and AS clause format correctly, and the function body gets indented as a block.
How does this compare to pgFormatter?
pgFormatter (the perl tool) is the most Postgres-aware formatter available and is worth installing if you run formatting in CI. Our browser tool is faster for ad-hoc formatting and handles 95% of what pgFormatter does without needing an install. Most developers use both — browser for quick checks, pgFormatter for CI.
Does the formatter handle WITH RECURSIVE CTEs?
Yes. Recursive CTEs get clear visual separation between the base case and the recursive case joined by UNION ALL. The termination condition (typically a WHERE clause in the recursive part) stays visible.

