SQLFormat SQL Formatter

PostgreSQL Query Formatter

Every character you typed survives -- this pass changes layout, never content. Pick PostgreSQL in the dialect box for queries like these and two readings flip in your favour: a bare # becomes integer XOR instead of a MySQL line comment, and a backslash inside single quotes stays a literal character, matching standard_conforming_strings (the default since 9.1). Everything else is the same engine-agnostic layout in every mode: JSONB path operators (#>, #>>, #-), -> and ->>, :: casts, DISTINCT ON, ILIKE, dollar-quoting and OVER (PARTITION BY ...) come through formatting and minifying intact.

SQL Query Formatter POSTGRES
Formatting Status
✓ Formatted SQL Query
0 chars
Raw SQL
Formatted SQL

What picking POSTGRES actually does

This formatter is one layout engine, not three parsers, and it will not rewrite your SQL into another dialect. Picking POSTGRES changes one thing: how two spellings that mean opposite things in two engines get read from the text — and it moves 3 of them away from the Auto reading. Everything on this page came out of that engine at build time, in this mode, so you can paste the same input and check it line for line.

A bare # between two operands

PostgreSQL spells integer bitwise XOR with #. MySQL reads the same byte as a line comment running to end of line. No parser can tell the two apart from the text alone, so the mode you pick decides which one survives.

Typed in

SELECT a # b FROM t;

Formatted in POSTGRES mode

SELECT a # b
FROM t;

The same text in Auto (MySQL-safe) mode

SELECT a
# b FROM t;

The same text in MySQL / MariaDB mode

SELECT a
# b FROM t;

The same text in SQLite mode

SELECT a
# b FROM t;

Minified in POSTGRES mode

SELECT a # b FROM t;

Minified in Auto (MySQL-safe) mode

SELECT a

Minified in MySQL / MariaDB mode

SELECT a

Minified in SQLite mode

SELECT a

This mode keeps # as an operator, so b FROM t stays attached to the expression. Under Auto or MySQL the same bytes comment out the rest of the line and that tail is simply gone.

A # comment above a clause

The same bytes are a comment in two of these modes and an operator in the third, and the difference is visible in where FROM t ends up.

Typed in

SELECT 1 # section
FROM t;

Formatted in POSTGRES mode

SELECT 1 # section
FROM t;

The same text in Auto (MySQL-safe) mode

SELECT 1
# section
FROM t;

The same text in MySQL / MariaDB mode

SELECT 1
# section
FROM t;

The same text in SQLite mode

SELECT 1
# section
FROM t;

Minified in POSTGRES mode

SELECT 1 # section FROM t;

Minified in Auto (MySQL-safe) mode

SELECT 1 FROM t;

Minified in MySQL / MariaDB mode

SELECT 1 FROM t;

Minified in SQLite mode

SELECT 1 FROM t;

Nothing here is a comment in PostgreSQL, so # section stays inside the select list as an expression. Auto lifts it onto its own line because it takes it for a comment.

A string literal ending in a backslash

The classic Windows-path case. If a backslash escapes the next character, the first literal runs past its closing quote and fuses with the next one — and the text between the quotes starts being treated as code.

Typed in

SELECT 'C:\' AS p, 'a FROM b' AS q FROM t;

Formatted in POSTGRES mode

SELECT 'C:\' AS p,
  'a FROM b' AS q
FROM t;

The same text in Auto (MySQL-safe) mode

SELECT 'C:\' AS p, 'a
FROM b' AS q FROM t;

The same text in MySQL / MariaDB mode

SELECT 'C:\' AS p, 'a
FROM b' AS q FROM t;

Minified in POSTGRES mode

SELECT 'C:\' AS p, 'a FROM b' AS q FROM t;

Minified in Auto (MySQL-safe) mode

SELECT 'C:\' AS p, ' a FROM b ' AS q FROM t;

Minified in MySQL / MariaDB mode

SELECT 'C:\' AS p, ' a FROM b ' AS q FROM t;

With standard_conforming_strings on — the default since PostgreSQL 9.1 — a backslash is just a character, so the first literal ends at its own closing quote and a FROM b stays a value of its own. The Auto reading fuses the two literals and reflows FROM inside what was a single string.

What does not change

POSTGRES constructs come through formatting and minifying with the same characters they went in with, in every mode. That is deliberate — the layout pass is engine-agnostic — but read it as "your tokens survive", never as "the tool understands POSTGRES". It cannot validate anything, and broken SQL will be prettified into something that looks correct.

One warning that applies in every mode

Minify is not a shrinker of meaning. It collapses the statement onto one line and deletes every comment style — --, # and block — so anything an audit trail or an EXPLAIN annotation relies on is gone rather than compressed.

SELECT 1 FROM t;

Frequently Asked Questions

Why does my PostgreSQL query lose everything after a # sign?

Because that # was read as a MySQL line comment. Auto keeps MySQL readings, so a bare # between two operands turns everything after it on that line into a comment: formatting keeps it, visibly, as a comment, and minifying deletes it outright. Pick PostgreSQL in the dialect box and # is integer bitwise XOR, so the expression stays attached and FROM moves back onto its own line. If your query has no # operator, the two modes give identical output.

Will the formatter break a Windows path stored in a string literal?

Not in PostgreSQL mode. With standard_conforming_strings on, which has been the default since 9.1, a backslash is an ordinary character, so a literal ending in one stops at its own closing quote. In Auto or MySQL mode that backslash escapes the closing quote instead, the literal fuses with whatever follows it, and the text between the two quotes gets reflowed as though it were code. Paste the same input in both modes to see it.

Does choosing PostgreSQL rewrite my SQL into standard SQL?

No, and that is deliberate. This is one layout pass that changes whitespace and keyword case, never tokens. DISTINCT ON, ILIKE, dollar-quoting, :: casts and JSONB path operators come through character-for-character in every mode, and nothing is validated — invalid SQL will be prettified into something that looks correct. Run it against your database before trusting it.

Developer Sponsor / Partner
Copied to clipboard!

🧭 Pro Tips & Gotchas

<!-- Per-route Pro Tips for /sql/postgres-formatter/. Deliberately does NOT repeat

content/sqlformat.md (the homepage panel): keyword-anchored layout, the

uppercase-identifier trap, window-clause reflow, comment deletion and the

"no parser" caveat all live there and are linked instead. Duplicating that

text here is what made the three dialect routes ~92% identical. Every bullet

below was run against apps/sqlformat/src/core.js before it was written. -->

The two readings that flip in this mode

Things this pass does that are worth a look before you commit

Where Postgres syntax gets layout, not understanding

RETURNING breaks onto its own line and a LATERAL subquery indents because both match as keywords, not because anything here knows PostgreSQL. Nothing is validated: a query with a missing comma comes out looking tidy and still fails at runtime. For anything machine-generated, use a real formatter and keep this for interactive work — see the [dialect differences guide](/guides/postgres-vs-mysql-dialects/) for the full list of what each engine means by the same character.