Blog
Wild & Free Tools

PostgreSQL SQL Formatter — Format Postgres Queries in Your Browser

Last updated: April 2026 8 min read

Table of Contents

  1. Why pgAdmin formatting falls short
  2. Postgres syntax we handle
  3. Format a Postgres query — step by step
  4. Common Postgres formatting wins
  5. Postgres formatter tool comparison
  6. Related tools for Postgres developers
  7. Frequently Asked Questions

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:

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

  1. Copy your query from pgAdmin, DBeaver, psql, or wherever you write it — even from a Slack message if a teammate sent it.
  2. Paste it into the formatter input — handles queries up to about 500KB.
  3. Set dialect to PostgreSQL — this enables JSONB operator handling and recursive CTE formatting.
  4. Pick indent — 2 or 4 spaces — Postgres community style guides vary. Pick what your team uses.
  5. Toggle uppercase keywords — most Postgres style guides use uppercase keywords. Leave the toggle on.
  6. 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 Shipping

Real-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

ToolCostPostgres SupportPrivacy
Hawk SQL Formatter (this tool)FreeNative PostgreSQL dialect, JSONB-aware100% browser, no upload
pgAdmin built-in formatIncludedBasic, breaks on JSONBStays in pgAdmin
DBeaver SQL formatterFreeGood but generic, not Postgres-awareLocal install
JetBrains DataGrip$229/yearStrong with Postgres driverLocal install
pgFormatter (perl CLI)Free, install requiredExcellent, Postgres-specificLocal
VS Code + Prisma extensionFreeGood for schema filesLocal

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 Formatter

Frequently 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.

Launch Your Own Clothing Brand — No Inventory, No Risk