PostgreSQL Formatter
Format Postgres SQL with dollar quoting, casts, CTEs and JSONB operators handled properly.
Your PostgreSQL
Formatted 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 to use the postgresql formatter
- 1
Paste the query, migration or function
A plain
SELECT, a chain of CTEs, aCREATE FUNCTIONwith a dollar-quoted body or a whole migration file all work. - 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
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::numericand'{"kind":"signup"}'::jsonbkeep 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 anUPDATE … FROM … RETURNING.- Window functions. The
OVER (PARTITION BY … ORDER BY …)body is broken out and indented, sorow_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.
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.
