PostgreSQL Formatter & Beautifier

PostgreSQL has one of the richest SQL dialects. ::type casting, RETURNING clauses, JSONB operators like ->, window functions, recursive CTEs — powerful but syntactically dense.

This PostgreSQL formatter and beautifier is tuned for the Postgres dialect: it formats Postgres SQL online, preserves cast operators, lays out RETURNING clauses cleanly, and handles CTEs without turning them into an indentation disaster. Everything runs in your browser.

📑 Table of Contents
  1. Why PostgreSQL-Specific Formatting
  2. Formatting Examples
  3. PostgreSQL Clauses Worth Formatting
  4. PostgreSQL Beautifier
  5. As a PostgreSQL Code Formatter
  6. pg_format, pgFormatter and psql
  7. Practical Tips
  8. Frequently Asked Questions

Why PostgreSQL-Specific Formatting

PostgreSQL differs from standard SQL in ways that affect formatting:

Generic formatters often add spaces around :: operators. The PostgreSQL dialect avoids this.

PostgreSQL Formatting Examples

Recursive CTE — Before

WITH RECURSIVE subordinates AS (SELECT id,name,manager_id FROM employees WHERE id=1 UNION ALL SELECT e.id,e.name,e.manager_id FROM employees e INNER JOIN subordinates s ON s.id=e.manager_id) SELECT * FROM subordinates;

After (PostgreSQL, 4 spaces)

WITH RECURSIVE subordinates AS (
  SELECT id, name, manager_id FROM employees WHERE id = 1
  UNION ALL
  SELECT e.id, e.name, e.manager_id
  FROM employees e
  INNER JOIN subordinates s ON s.id = e.manager_id
)
SELECT * FROM subordinates;

The recursive CTE structure is now visible — anchor query on top, recursive member below, final SELECT at the bottom.

PostgreSQL Clauses Worth Formatting

Beyond casting and CTEs, everyday Postgres work is full of clauses that collapse into unreadable one-liners. A PostgreSQL-aware formatter gives each clause its own line so you can scan the intent at a glance.

Upsert with ON CONFLICT ... RETURNING

INSERT INTO inventory (product_id, quantity) VALUES (42, 10) ON CONFLICT (product_id) DO UPDATE SET quantity = inventory.quantity + EXCLUDED.quantity RETURNING product_id, quantity AS new_qty;

After (PostgreSQL, 4 spaces)

INSERT INTO inventory (product_id, quantity)
VALUES (42, 10)
ON CONFLICT (product_id)
DO UPDATE
SET quantity = inventory.quantity + EXCLUDED.quantity
RETURNING product_id, quantity AS new_qty;

The conflict target, the update branch, and the RETURNING clause each sit on their own line — exactly how a reviewer wants to read an upsert. The formatter keeps EXCLUDED references intact and does not mangle the + expression.

Other Postgres-only constructs handled cleanly

These are the constructs that break under naive formatters. When the output survives a copy-paste back into psql or your migration runner without errors, you know the dialect support is doing its job.

PostgreSQL Beautifier: Readable Layout, Same Query

A PostgreSQL beautifier takes SQL that works but reads like a wall of text and hands back the same statement with line breaks and indentation a human can follow. Nothing is renamed, no clause is reordered, and no space appears around :: casts or JSONB operators — whitespace is the only thing that changes.

Paste a query from a ticket, a slow-query log, or a legacy migration, pick PostgreSQL as the dialect and 4 spaces of indentation, and the output matches what most Postgres shops already write by hand: one clause per line, join conditions attached to their join, subqueries indented inside their parentheses. The dialect setting is what separates this from a generic beautifier — generic tools happily insert a space after :: and hand you back a statement Postgres refuses to parse.

Where a PostgreSQL beautifier earns its keep

Need the opposite — a single-line statement for a script — run the result through the SQL minifier.

Using It as a PostgreSQL Code Formatter

As a project-wide PostgreSQL code formatter, consistency matters more than taste: the same input should always produce the same output, so diffs show real changes instead of reflowed lines. Two controls decide the layout — dialect (PostgreSQL) and indentation (2 spaces, 4 spaces, or tabs). Pick one per repository and every file matches, whether it came from a human, an ORM log, or a dump.

What it is useful for beyond one query

All of it runs client-side, so the query text never leaves your machine. That matters when the statement carries table names, column names, or customer identifiers you would rather not paste into a server-side tool.

pg_format, pgFormatter and psql: CLI Tools vs an Online Formatter

Searching for "format psql" or "pg_format" usually means you already know the command-line route. The established options:

CLI tools are the right answer when formatting runs as part of a build. They are the wrong answer when you cannot install Perl or Docker on the machine in front of you, when you are reviewing someone else's query in a browser tab, or when you just want to see one statement laid out before pasting it back into chat.

Getting a psql-style readable layout

If what you want is psql-like readability — clauses on their own lines, joins and subqueries indented, RETURNING aligned with the statement it belongs to — select PostgreSQL and 4 spaces above. The result survives copy-paste back into psql, a migration runner, or an EXPLAIN ANALYZE session unchanged. To read the plan that comes back, use the EXPLAIN visualizer; to confirm the statement parses first, use the PostgreSQL syntax checker.

Practical Tips for Postgres Users

Validate PostgreSQL syntax before you format

Run the query through the PostgreSQL syntax checker first — a statement that does not parse produces neat but broken output. The validator understands RETURNING, :: casts, DISTINCT ON, LATERAL joins and JSONB operators such as @> and ->>, all of which get flagged if you check them under MySQL or Standard SQL. Fix the reported line, then format.

Format pg_dump output

pg_dump --schema-only output is functional but ugly. Formatting it section by section — tables, indexes, functions — makes reviewing database changes much easier.

Audit JSONB queries

When working with JSONB-heavy queries, format the SQL first, then trace the path expressions to verify they target the right nested keys. Clean formatting makes this kind of auditing practical.

💡 Pro tip: If you use psql with \x auto for expanded display, formatted queries are much easier to align with the expanded output format.

Frequently Asked Questions

Does this formatter handle ::type casting?

Yes. The PostgreSQL dialect preserves ::text, ::integer, and other cast operators without adding spaces around the :: operator, which would break the syntax.

Can it format PL/pgSQL functions?

Yes. The formatter handles CREATE FUNCTION blocks with LANGUAGE plpgsql and preserves $$ dollar-quoted function bodies.

Does it work with recursive CTEs?

Yes. Recursive CTEs are formatted with clear visual separation between the anchor member and the recursive member.

Does it support INSERT ... ON CONFLICT ... RETURNING?

Yes. Upserts keep ON CONFLICT on its own line with the DO UPDATE or DO NOTHING branch readable, and RETURNING stays aligned with the rest of the statement.

Does it preserve PostgreSQL-specific operators?

Yes. Array and JSONB operators such as @>, ?|, and ->>, plus ILIKE, keep their exact spacing so the query still runs after formatting.

Is this a PostgreSQL beautifier as well as a formatter?

Yes. Beautifier and formatter describe the same operation here: indentation and line breaks change, nothing else. You get a pretty-printed version of the statement you pasted.

Do I need to install pg_format or pgFormatter to use it?

No. The formatter runs entirely in your browser with no installation, account, or upload. Reach for the CLI tools when formatting has to happen inside a build pipeline.

Can I format psql output, pg_dump output, or a migration file?

Yes. Paste statement text from psql, a pg_dump --schema-only dump, or a migration file. For very large dumps, format it in sections or use the large-file page.

Does formatting change what the query does?

No. Only whitespace and line breaks are rewritten. Keywords, identifiers, string literals, and operators are left exactly as typed, so the formatted statement behaves the same as the original.

🧹 Try It Now