SQL

PostgreSQL Formatter

Format Postgres SQL with dollar quoting, casts, CTEs and JSONB operators handled properly.

Private by design — your data never leaves your device.
✓ Free forever✓ No sign-up✓ No ads✓ Works offline once loaded

PostgreSQL Formatter

Format Postgres SQL with dollar quoting, casts, CTEs and JSONB operators handled properly.

Input

Your PostgreSQL

Nothing is uploaded.

Output

Formatted PostgreSQL

Your result appears herePaste on the left and select “Format PostgreSQL”

PostgreSQL rewards writing queries that are structurally complex — chained CTEs, window functions, lateral joins, RETURNING clauses that hand data straight back from a write. All of that is exactly the SQL that becomes unreadable when it collapses onto one line, which is what happens the moment it passes through a log, a migration tool or a Slack message.

With the PostgreSQL dialect selected, this formatter knows the syntax the generic parser rejects: dollar-quoted function bodies, the :: cast shorthand, JSON and JSONB operators built out of characters that look like arithmetic, and array subscripting. Everything is processed locally in your browser.

How it works

How to use the postgresql formatter

  1. 1

    Paste the query, migration or function

    A plain SELECT, a chain of CTEs, a CREATE FUNCTION with a dollar-quoted body or a whole migration file all work.

  2. 2

    Choose indentation and keyword case

    Four spaces suits deeply nested CTEs; two keeps wide window function definitions on screen. Keyword case can be upper, lower or preserved.

  3. 3

    Read the CTE chain top to bottom

    Each CTE body is indented inside its parentheses, so a five-step transformation reads as five steps instead of one paragraph.

Postgres syntax that trips generic formatters

  • Dollar quoting. A function body written as $$ … $$ or $body$ … $body$ is treated as one opaque token. It is passed through byte for byte and deliberately not re-indented, because the contents may be PL/pgSQL, Python, or anything else a language handler accepts — reformatting it as SQL would be a guess. A generic parser does not recognise the delimiter at all and fails on the first $.
  • :: casts. score::numeric and '{"kind":"signup"}'::jsonb keep the value and its target type glued together, rather than being split as if : were an operator.
  • JSON and JSONB operators. -> returns a JSON value, ->> returns text, #> and #>> take a path, and @> tests containment. These are tokenised as operators and spaced consistently instead of being mangled into comparison signs.
  • RETURNING. Given its own top-level clause line, with each returned column on its own row — which is where you look first when reading an UPDATE … FROM … RETURNING.
  • Window functions. The OVER (PARTITION BY … ORDER BY …) body is broken out and indented, so row_number() over a wide partition stops being a single 200-character expression.
  • Arrays and ranges. ARRAY[…] constructors, subscripts and range types are preserved as written.

Identifier case is not cosmetic in Postgres

PostgreSQL folds unquoted identifiers to lower case, while the SQL standard says fold to upper case. That is why SELECT MyColumn resolves to mycolumn, and why a column created as "MyColumn" can only ever be referenced with the quotes intact.

The formatter therefore never touches identifier case. The keyword case control applies to reserved words only. If your schema was created from an ORM that quoted every identifier, expect quoted mixed-case names in the output — that is the query you have, and rewriting them would break it.

PL/pgSQL bodies are passed through, not formatted

A CREATE FUNCTION statement is formatted as a SQL statement: the signature, return type, language and volatility markers are laid out, and the dollar-quoted body is emitted unchanged on one line if that is how you wrote it. This is a deliberate limit rather than an oversight — the body is a different language with its own block structure, and a SQL pretty-printer has no business rewriting it.

If you want the body itself laid out, format its inner SQL separately and paste it back between the dollar quotes.

Common questions

PostgreSQL Formatter FAQ

Does it handle dollar-quoted strings?

Yes, both the anonymous $$ form and tagged forms like $body$. The contents are preserved exactly and are not reformatted, because they may not be SQL at all.

Will it rewrite :: casts as CAST(...)?

No. The formatter only changes whitespace and keyword casing. Converting between :: and CAST would be a rewrite, and :: is by far the more common style in Postgres codebases.

Does it work for Redshift or Greenplum?

Mostly, since both descend from PostgreSQL. Redshift has its own entry in the dialect selector on the main SQL formatter, which is a better fit if your query uses Redshift-specific syntax such as DISTKEY and SORTKEY.

Are my queries sent to a server?

No. Tokenising and printing happen in JavaScript in your browser. There is no backend to receive a query, which matters when the WHERE clause contains real customer identifiers.

Why is my mixed-case column still quoted in the output?

Because removing the quotes would change which column Postgres resolves. Unquoted identifiers fold to lower case, so "MyColumn" and MyColumn are two different columns.