Beta — covers the core PostgreSQL DML and DDL statement set. A number of uncommon top-level statements (e.g.
CREATE CAST,ALTER DOMAIN,CREATE CONVERSION,CREATE STATISTICS,CREATE TEXT SEARCH …,CREATE OPERATOR CLASS,ALTER DEFAULT PRIVILEGES,CREATE / ALTER / DROP DATABASE,CREATE FOREIGN DATA WRAPPER) have no printer yet and are kept exactly as written (case and spacing included) instead. Inside a statement the formatter has a printer for, a construct it can't print raises an explicitUnsupported …error (for example a type modifier that is an expression,foo(1 + 1)) — it never silently drops or changes anything. The test suite enforces this by comparing the PostgreSQL parse tree before and after formatting.
A Prettier plugin for PostgreSQL SQL. Parses SQL with libpg_query (the actual PostgreSQL parser) and formats it using Prettier's document IR for consistent, readable output.
- SELECT — column lists, table aliases, all JOIN types (INNER, LEFT, RIGHT, FULL, CROSS, NATURAL), WHERE, GROUP BY / HAVING, ORDER BY, LIMIT / OFFSET, FETCH FIRST … WITH TIES, DISTINCT, DISTINCT ON
- Set operations — UNION / UNION ALL / INTERSECT / EXCEPT, with WITH / ORDER BY / LIMIT applying to the whole result, and operands parenthesized where they need to be
- VALUES — standalone, with WITH, ORDER BY and LIMIT
- Subqueries — correlated subqueries, EXISTS, scalar sublinks,
ARRAY(subquery), row comparisons ((a, b) < (SELECT …)), LATERAL - CTEs — WITH / WITH RECURSIVE, data-modifying CTEs (WITH ... DELETE/INSERT/UPDATE)
- Window functions — OVER (PARTITION BY, ORDER BY, frame clauses: ROWS/RANGE/GROUPS BETWEEN)
- Aggregate functions — FILTER (WHERE ...), ORDER BY inside aggregate (e.g.
string_agg) - GROUP BY extensions — ROLLUP, CUBE, GROUPING SETS
- Locking — FOR UPDATE / FOR SHARE / FOR NO KEY UPDATE / FOR KEY SHARE with OF, NOWAIT, SKIP LOCKED
- INSERT — VALUES (single and multi-row), DEFAULT VALUES, ON CONFLICT DO NOTHING / DO UPDATE SET (conflict targets can be expressions, and a WHERE matches a partial unique index), RETURNING, OVERRIDING USER/SYSTEM VALUE,
DEFAULTin VALUES, subscript / field targets (insert into t (a.b)), WITH clause - UPDATE — SET (including multi-column
SET (a, b) = (…)/= (SELECT …),DEFAULT, and subscript / field targets likea[1] = 2), FROM, WHERE (includingWHERE CURRENT OF cursor), RETURNING, WITH clause - DELETE — WHERE (including
CURRENT OF), RETURNING, WITH clause - TRUNCATE — with RESTART IDENTITY and CASCADE
- Transaction control — BEGIN / START TRANSACTION / COMMIT / ROLLBACK (with AND CHAIN) / SAVEPOINT / RELEASE SAVEPOINT / ROLLBACK TO SAVEPOINT / SET TRANSACTION (isolation level, READ ONLY/WRITE, DEFERRABLE) / PREPARE TRANSACTION / COMMIT PREPARED / ROLLBACK PREPARED
- MERGE — WHEN MATCHED / WHEN NOT MATCHED / WHEN NOT MATCHED BY SOURCE; UPDATE SET, INSERT, DELETE, DO NOTHING actions; conditional AND clause; OVERRIDING in INSERT; RETURNING with
merge_action() - CALL — stored-procedure invocation
- CREATE TABLE — column definitions with full constraint support: NOT NULL, DEFAULT, PRIMARY KEY, FOREIGN KEY (column-level and table-level, with MATCH FULL/PARTIAL and ON UPDATE/DELETE actions, including
SET NULL (cols)), CHECK (with NO INHERIT), UNIQUE (with NULLS NOT DISTINCT), EXCLUDE (USING gist (col WITH op, …) WHERE (…)), GENERATED ALWAYS AS (stored), GENERATED AS IDENTITY (with sequence options), named constraints, DEFERRABLE / INITIALLY DEFERRED; index parameters (INCLUDE, WITH (…), USING INDEX TABLESPACE);COLLATE, STORAGE and COMPRESSION column clauses, typed tables (OF typewithWITH OPTIONS), type modifiers (VARCHAR(100),NUMERIC(10,2); a modifier that is an expression is unsupported), array types (TEXT[],INT[3]). Types written with SQL keywords get their standard spelling (int→integer); internal names (int4,float8,"char") are kept as written - ALTER TABLE (and INDEX / VIEW / MATERIALIZED VIEW / FOREIGN TABLE / SEQUENCE) — every subcommand libpg_query produces: ADD / DROP COLUMN, ADD / DROP / VALIDATE / ALTER CONSTRAINT, ALTER COLUMN TYPE … COLLATE … USING, SET / DROP DEFAULT, SET / DROP NOT NULL, identity (
ADD GENERATED,SET GENERATED,RESTART,DROP IDENTITY),DROP / SET EXPRESSION, SET STATISTICS / STORAGE / COMPRESSION, SET / RESET (options), trigger and rule enable / disable, row level security, CLUSTER ON, SET LOGGED / UNLOGGED, INHERIT, OF, REPLICA IDENTITY, ATTACH / DETACH PARTITION, OWNER TO, SET TABLESPACE, foreign table OPTIONS - ALTER … RENAME — every object kind: tables (IF EXISTS, ONLY), columns, constraints, indexes, views, sequences, schemas, databases, roles, triggers / policies / rules
ON table, type attributes, domain constraints, operator classesUSING method, functions, aggregates, and more - CREATE VIEW / CREATE MATERIALIZED VIEW
- CREATE TABLE AS —
CREATE TABLE foo AS SELECT ... - CREATE INDEX / CREATE UNIQUE INDEX
- CREATE FUNCTION / PROCEDURE — RETURNS, LANGUAGE, dollar-quoted
$$...$$body, SQL-standard bodies (RETURN expr,BEGIN ATOMIC … END), TRANSFORM FOR TYPE, parameter lists with modes (IN, OUT, INOUT, VARIADIC) and%TYPE - CREATE TYPE — composite (
AS (...)) and enum (AS ENUM (...)) - ALTER TYPE — ADD VALUE for enums (with BEFORE/AFTER placement, IF NOT EXISTS), RENAME VALUE; ADD / DROP / ALTER ATTRIBUTE for composite types
- CREATE / ALTER SEQUENCE — START WITH, INCREMENT BY, MINVALUE, MAXVALUE, CACHE, CYCLE, RESTART WITH
- CREATE SCHEMA — with IF NOT EXISTS and AUTHORIZATION, and the objects created inside it (
CREATE TABLE … CREATE VIEW …) - CREATE EXTENSION — with IF NOT EXISTS
- CREATE TRIGGER — BEFORE/AFTER/INSTEAD OF, INSERT/UPDATE/DELETE/TRUNCATE, FOR EACH ROW/STATEMENT
- DROP — any object: TABLE, VIEW, INDEX (CONCURRENTLY), FUNCTION, TYPE, SCHEMA, …;
TRIGGER / POLICY / RULE … ON table,OPERATOR CLASS / FAMILY … USING method,CAST (a AS b),TRANSFORM FOR type LANGUAGE lang,AGGREGATE agg(*); function and aggregate signatures keep their argument modes and names (f(IN a int, OUT b text),VARIADIC) - GRANT / REVOKE — every object kind (TABLE, SCHEMA, FUNCTION / PROCEDURE with argument modes, SEQUENCE, FOREIGN SERVER, TYPE, DOMAIN, LARGE OBJECT, PARAMETER,
ALL … IN SCHEMA, …); WITH GRANT OPTION; CASCADE - CREATE / ALTER ROLE — with LOGIN, PASSWORD, SUPERUSER, CREATEDB, CREATEROLE, INHERIT, REPLICATION, BYPASSRLS, CONNECTION LIMIT
- COMMENT ON — every object kind, including constraints, triggers, rules and policies
ON table, domain constraints, operator classes / familiesUSING method, transforms, casts, aggregates, large objects (by OID), and routine signatures with argument modes - CREATE TABLE LIKE —
CREATE TABLE new (LIKE existing INCLUDING ALL) - Table partitioning —
PARTITION BY RANGE/LIST/HASH(with expression elements,COLLATEand operator class),CREATE TABLE ... PARTITION OF(with columns and storage; also for foreign tables), partition bounds (FOR VALUES FROM/TO,IN,WITH,DEFAULT) with expressions (date '2020-01-01') - TABLESAMPLE —
FROM t TABLESAMPLE BERNOULLI(10)/SYSTEM(5) REPEATABLE (42) - VACUUM / ANALYZE / CLUSTER / REINDEX — maintenance statements with options, including option values (
VACUUM (PARALLEL 4, INDEX_CLEANUP off)) - CHECKPOINT —
CHECKPOINT - LOAD —
LOAD 'filename' - CREATE / DROP TABLESPACE —
CREATE TABLESPACE name LOCATION path,DROP TABLESPACE [IF EXISTS] name - Foreign data wrappers —
CREATE SERVER,CREATE FOREIGN TABLE(withPARTITION OF,INHERITS, columnOPTIONS),CREATE USER MAPPING,IMPORT FOREIGN SCHEMA - Logical replication —
CREATE / ALTER / DROP PUBLICATIONandSUBSCRIPTION - CREATE AGGREGATE —
CREATE [OR REPLACE] AGGREGATE name (args [ORDER BY …]) (SFUNC = ..., STYPE = ...), including ordered-set andVARIADICarguments - CREATE OPERATOR —
CREATE OPERATOR op (LEFTARG = ..., PROCEDURE = ...) - CREATE COLLATION —
CREATE COLLATION name (LOCALE = ...)andFROM existing - SECURITY LABEL —
SECURITY LABEL FOR provider ON object IS labelfor every object kind
- SQL standard functions —
SUBSTRING(str FROM pattern),EXTRACT(field FROM expr),TRIM(LEADING/TRAILING/BOTH ... FROM str),POSITION(x IN y),expr AT TIME ZONE tz,OVERLAY(...),(a, b) OVERLAPS (c, d),x IS [NOT] NFC NORMALIZED,NORMALIZE(x, NFC),SYSTEM_USER,COLLATION FOR (x) - Collation and literals —
expr COLLATE "C", bit strings (B'101',X'ff'),DEFAULTin VALUES / SET - Type casting —
expr::type(PostgreSQL style),INTERVAL '1 day'literals with optional field modifiers (HOUR TO MINUTE,DAY TO SECOND, etc.) - Operators — schema-qualified
OPERATOR(pg_catalog.+), including in ANY / ALL - Row values and fields —
ROW(a, b),(a, b), field selection(composite).fieldand(f(x)).* - Array subscripts —
arr[1],arr[2:4],arr[:3] - Named arguments —
func(param => value),func(VARIADIC arr) - Ordered-set aggregates —
percentile_cont(0.5) WITHIN GROUP (ORDER BY x) - Conditional — CASE / WHEN / THEN / ELSE, COALESCE, NULLIF, GREATEST, LEAST
- XML functions —
XMLELEMENT(withXMLATTRIBUTES),XMLFOREST,XMLCONCAT,XMLPI,XMLAGG,XMLEXISTS,IS DOCUMENT - XMLTABLE — tabular XML query in the
FROMclause;XMLNAMESPACES, alias column lists,PASSING,COLUMNSwithPATH,DEFAULT,NOT NULL,FOR ORDINALITY - SQL/JSON functions —
JSON_QUERY,JSON_EXISTS,JSON_VALUEwithFORMAT JSON,PASSING,RETURNING,WITH / WITHOUT WRAPPER,KEEP / OMIT QUOTES, and… ON EMPTY/… ON ERROR(includingDEFAULT expr) — PostgreSQL 16+ - SQL/JSON constructors and predicates —
x IS [NOT] JSON [VALUE | ARRAY | OBJECT | SCALAR] [WITH UNIQUE KEYS],JSON,JSON_SCALAR,JSON_SERIALIZE,JSON_OBJECT,JSON_ARRAY(alsoJSON_ARRAY(SELECT …)),JSON_OBJECTAGG,JSON_ARRAYAGGwithFORMAT JSONvalues,ABSENT / NULL ON NULL,WITH UNIQUE KEYS,RETURNING, and aggregateORDER BY/FILTER/OVER— PostgreSQL 16+ - JSON_TABLE — tabular JSON query in the
FROMclause;PASSING,PATH,EXISTS PATH,FORMAT JSON PATH,NESTED PATH … AS name,FOR ORDINALITY, wrapper and quotes options,ON EMPTY/ON ERROR— PostgreSQL 16+ - Predicates — IN / NOT IN, BETWEEN / NOT BETWEEN, LIKE / NOT LIKE, ILIKE / NOT ILIKE, SIMILAR TO, IS NULL / IS NOT NULL, IS DISTINCT FROM, ANY / ALL
- SQL value functions — CURRENT_DATE, CURRENT_TIMESTAMP, CURRENT_USER, SESSION_USER, LOCALTIME, LOCALTIMESTAMP, and others, with precision (
CURRENT_TIMESTAMP(0)) - GROUPING() —
GROUPING(col)predicate used alongside GROUPING SETS
- SET / SHOW / RESET —
SET search_path = myschema,SET TIME ZONE INTERVAL '1' HOUR TO MINUTE,SHOW work_mem,RESET ALL - ALTER SYSTEM —
ALTER SYSTEM SET param = value,ALTER SYSTEM RESET [ALL]— writes topostgresql.conf - DISCARD —
DISCARD ALL,DISCARD PLANS,DISCARD SEQUENCES,DISCARD TEMP - SELECT INTO —
SELECT ... INTO [TEMP | UNLOGGED] table - COPY —
COPY table FROM/TO,COPY (query) TO; program and option list - EXPLAIN —
EXPLAIN,EXPLAIN ANALYZE,EXPLAIN (ANALYZE, VERBOSE, FORMAT JSON) stmt - PREPARE / EXECUTE / DEALLOCATE — server-side prepared statements
- LISTEN / UNLISTEN / NOTIFY — async pub/sub with optional payload
- LOCK TABLE —
LOCK TABLE t IN ACCESS EXCLUSIVE MODE [NOWAIT] - Cursors —
DECLARE CURSOR,FETCH,MOVE,CLOSE - Comment preservation — a script made only of comments is kept; line comments (
-- ...) and block comments (/* ... */) are preserved: leading comments before a statement stay before it; inline trailing comments stay on the statement's final line - Meaning preserved — the test suite checks that formatting never changes what a statement means: every fixture's PostgreSQL parse tree must be the same before and after
- ALTER GROUP / ALTER LARGE OBJECT —
ADD USER/DROP USERmembers, large object OIDs,OWNER TO current_user - ALTER FUNCTION — SET COST, SET ROWS, SET VOLATILE/STABLE/IMMUTABLE, RENAME TO, OWNER TO, SET SCHEMA
- REFRESH MATERIALIZED VIEW — with CONCURRENTLY
- CREATE RULE — BEFORE/AFTER/INSTEAD, INSERT/UPDATE/DELETE/SELECT, DO ALSO/INSTEAD
- Row Security Policies —
CREATE / ALTER POLICYwith USING and WITH CHECK - REASSIGN OWNED —
REASSIGN OWNED BY old_role TO new_role - DROP OWNED —
DROP OWNED BY roles [CASCADE]
| Feature | Notes |
|---|---|
| PL/pgSQL | Full procedural language (IF/ELSIF, LOOP, RETURN, EXCEPTION, DECLARE) — out of scope for a SQL formatter |
| Requirement | Version |
|---|---|
| Node.js | 20 or later |
| .NET Runtime | 8.0 or later |
| Prettier | 3.x |
npm install --save-dev prettier prettier-plugin-postgresqlThen add the plugin to your Prettier configuration:
// prettier.config.js
export default {
plugins: ['prettier-plugin-postgresql'],
overrides: [
{
files: ['*.sql', '*.pgsql'],
options: {
parser: 'pgsql',
},
},
],
};See Getting Started for VS Code setup and build-from-source instructions.
Input (unformatted):
SELECT id,title,price,author_id FROM books WHERE in_stock=TRUE AND price<50 ORDER BY price ASC;Output (default options — lowercase keywords, standard density, trailing commas):
select
id,
title,
price,
author_id
from books
where
in_stock = true
and price < 50
order by price asc;Three formatting options are available. See Options for full details and examples.
| Option | Values | Default | Description |
|---|---|---|---|
sqlKeywordCase |
lower | upper | preserve |
lower |
Case for SQL keywords |
sqlDensity |
compact | standard | spacious |
standard |
Whitespace density |
sqlCommaStyle |
trailing | leading |
trailing |
Comma placement in lists |
// prettier.config.js
export default {
plugins: ['prettier-plugin-postgresql'],
overrides: [
{
files: '*.sql',
options: {
parser: 'pgsql',
sqlKeywordCase: 'upper',
sqlDensity: 'standard',
sqlCommaStyle: 'trailing',
},
},
],
};- Getting Started — installation, VS Code setup, building from source
- Options — all formatting options with examples
- Examples — before/after formatting examples for common patterns
- Formatting Reference — comprehensive formatting rules by statement type