All tools
Free

A searchable, printable PostgreSQL reference — psql commands, JSONB, arrays, CTEs, window functions, indexes, roles and EXPLAIN. Free.

psql meta-commands

15
psql -U user -d mydb -h localhost
Connect to a database
\l
List all databases
\c mydb
Switch to another database
\dt
List tables in current schema
\d users
Describe a table (columns, indexes)
\d+ users
Describe with size and storage
\dn
List schemas
\df
List functions
\du
List roles and their attributes
\x
Toggle expanded (vertical) output
\timing
Toggle query execution timing
\e
Edit the query buffer in $EDITOR
\i script.sql
Run SQL from a file
\copy users TO 'users.csv' CSV HEADER
Export a table to CSV
\q
Quit psql

Querying

10
SELECT * FROM users LIMIT 10;
First 10 rows
WHERE name ILIKE '%ann%'
Case-insensitive pattern match
WHERE name ~* '^a.*z$'
Regex match (case-insensitive)
ORDER BY score DESC NULLS LAST
Control where nulls sort
SELECT DISTINCT ON (user_id) * FROM orders ORDER BY user_id, created_at DESC;
Latest row per group
LIMIT 10 OFFSET 20
Paginate results
FETCH FIRST 5 ROWS ONLY
SQL-standard limit
SELECT ... FOR UPDATE SKIP LOCKED
Queue-style row locking
TABLESAMPLE SYSTEM (1)
Sample ~1% of a table
LATERAL (SELECT ... LIMIT 3)
Per-row correlated subquery

JSONB

14
data->'user'
Get JSON field (as jsonb)
data->>'name'
Get JSON field as text
data#>>'{user,address,city}'
Get nested value by path as text
data @> '{"active": true}'
Contains — matches subdocument
data ? 'email'
Key exists at top level
data ?| array['a', 'b']
Any of the keys exist
jsonb_set(data, '{name}', '"Sam"')
Update a value by path
data - 'legacy_field'
Delete a key
data || '{"active": true}'
Merge/overwrite fields
jsonb_array_elements(data->'items')
Expand array to rows
jsonb_each(data)
Expand object to key/value rows
jsonb_build_object('id', id, 'name', name)
Build JSON from columns
jsonb_agg(row_to_json(t))
Aggregate rows into a JSON array
jsonb_pretty(data)
Pretty-print for debugging

Arrays & ranges

13
tags TEXT[]
Declare an array column
ARRAY['a', 'b', 'c']
Array literal
tags[1]
Element access (1-based!)
WHERE 'php' = ANY(tags)
Array contains a value
WHERE tags @> ARRAY['php','sql']
Array contains all values
WHERE tags && ARRAY['php','go']
Arrays overlap (share any)
array_agg(name ORDER BY name)
Aggregate values into an array
unnest(tags)
Expand array to rows
array_length(tags, 1)
Number of elements
string_to_array('a,b', ',')
Split text into an array
period tstzrange
Timestamp range column
WHERE period @> now()
Range contains a value
EXCLUDE USING gist (room WITH =, period WITH &&)
No overlapping bookings

CTEs & window functions

12
WITH recent AS (SELECT ...) SELECT * FROM recent;
Common table expression
WITH RECURSIVE tree AS (... UNION ALL ...)
Walk hierarchies/graphs
WITH del AS (DELETE ... RETURNING *) INSERT ...
Data-modifying CTE
ROW_NUMBER() OVER (ORDER BY score DESC)
Sequential rank, no ties
RANK() / DENSE_RANK() OVER (...)
Rankings with tie handling
OVER (PARTITION BY user_id ORDER BY at)
Window per group
LAG(price) OVER (ORDER BY day)
Previous row's value
LEAD(price, 2) OVER (...)
Value 2 rows ahead
SUM(amount) OVER (ORDER BY day)
Running total
AVG(x) OVER (ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)
7-row moving average
NTILE(4) OVER (ORDER BY score)
Split rows into quartiles
FIRST_VALUE(name) OVER (...)
First value in the window

Upsert & RETURNING

9
INSERT ... ON CONFLICT (email) DO UPDATE SET name = EXCLUDED.name;
Upsert on a unique column
ON CONFLICT DO NOTHING
Silently skip duplicates
ON CONFLICT ON CONSTRAINT users_pkey DO UPDATE ...
Target a named constraint
EXCLUDED.column
The value that failed to insert
DO UPDATE ... WHERE users.updated_at < EXCLUDED.updated_at
Conditional upsert
INSERT ... RETURNING id;
Get generated ids back
UPDATE ... RETURNING *;
Return the updated rows
DELETE ... RETURNING id, email;
Return what was deleted
MERGE INTO t USING src ON ... (PG 15+)
SQL-standard merge

Data types

13
id BIGINT GENERATED ALWAYS AS IDENTITY
Modern auto-increment (prefer)
SERIAL / BIGSERIAL
Legacy auto-increment (sequence)
UUID DEFAULT gen_random_uuid()
Native UUID with generator
TEXT
Unlimited string — no VARCHAR(n) needed
NUMERIC(10, 2)
Exact decimal (money math)
TIMESTAMPTZ
Timestamp with time zone (prefer)
INTERVAL '2 days 3 hours'
Duration type, date arithmetic
BOOLEAN
True/false/null (real type)
JSONB
Binary JSON — indexable, prefer over JSON
BYTEA
Raw binary data
INET / CIDR / MACADDR
Network address types
CREATE TYPE status AS ENUM ('new', 'done');
Custom enum type
col TEXT GENERATED ALWAYS AS (lower(email)) STORED
Generated column

Indexes

12
CREATE INDEX idx_users_email ON users (email);
Default B-tree index
CREATE UNIQUE INDEX ... ON users (lower(email));
Unique expression index
CREATE INDEX ... ON orders (user_id) WHERE status = 'open';
Partial index
CREATE INDEX ... USING gin (data);
GIN — jsonb/array containment
CREATE INDEX ... USING gin (to_tsvector('english', body));
Full-text search index
CREATE INDEX ... USING gist (location);
GiST — geometry, ranges, KNN
CREATE INDEX ... USING brin (created_at);
BRIN — huge append-only tables
CREATE INDEX CONCURRENTLY ...
Build without locking writes
CREATE INDEX ... ON t (a, b DESC);
Composite with sort direction
CREATE INDEX ... ON t (a) INCLUDE (b);
Covering index (index-only scan)
REINDEX INDEX CONCURRENTLY idx_name;
Rebuild a bloated index
DROP INDEX CONCURRENTLY idx_name;
Remove without blocking

Roles & privileges

11
CREATE ROLE app LOGIN PASSWORD 'secret';
Create a login role (user)
CREATE ROLE readonly NOLOGIN;
Create a group role
GRANT readonly TO app;
Add a role to a group
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;
Bulk grant reads
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly;
Auto-grant future tables
GRANT USAGE ON SCHEMA public TO app;
Allow schema access
REVOKE INSERT ON users FROM app;
Remove a privilege
ALTER ROLE app SET statement_timeout = '30s';
Per-role setting
ALTER TABLE users OWNER TO app;
Change object owner
ALTER TABLE docs ENABLE ROW LEVEL SECURITY;
Turn on row-level security
CREATE POLICY own ON docs USING (owner_id = current_user_id());
RLS policy

Maintenance & EXPLAIN

12
EXPLAIN SELECT ...;
Show the planned query plan
EXPLAIN (ANALYZE, BUFFERS) SELECT ...;
Run it and show real timings
VACUUM (VERBOSE) users;
Reclaim dead-row space
VACUUM FULL users;
Rewrite table (locks it!)
ANALYZE users;
Refresh planner statistics
SELECT * FROM pg_stat_activity;
List running queries
SELECT pg_cancel_backend(pid);
Cancel a running query
SELECT pg_terminate_backend(pid);
Kill a connection
SELECT pg_size_pretty(pg_total_relation_size('users'));
Table size incl. indexes
SELECT pg_size_pretty(pg_database_size('mydb'));
Whole database size
SELECT * FROM pg_stat_user_indexes;
Spot unused indexes
SELECT * FROM pg_locks WHERE NOT granted;
Find blocked lock waits

Backup & restore

12
pg_dump mydb > mydb.sql
Plain-SQL dump of a database
pg_dump -Fc mydb > mydb.dump
Custom format (compressed)
pg_dump -Fd mydb -j 4 -f dumpdir/
Directory format, 4 parallel jobs
pg_dump -t users -t orders mydb
Dump specific tables only
pg_dump --schema-only mydb
Structure without data
pg_dump --data-only mydb
Data without structure
psql mydb < mydb.sql
Restore a plain-SQL dump
pg_restore -d mydb -j 4 mydb.dump
Restore custom format in parallel
pg_restore -l mydb.dump
List dump contents
pg_restore -t users -d mydb mydb.dump
Restore a single table
pg_dumpall --globals-only > roles.sql
Back up roles and tablespaces
pg_basebackup -D /backup -Fp -Xs -P
Physical base backup (PITR)

Extensions

11
CREATE EXTENSION IF NOT EXISTS pgcrypto;
Hashing, encryption functions
CREATE EXTENSION "uuid-ossp";
uuid_generate_v4() and friends
CREATE EXTENSION pg_stat_statements;
Track query performance stats
CREATE EXTENSION pg_trgm;
Trigram fuzzy search + LIKE index
CREATE EXTENSION postgis;
Geospatial types and queries
CREATE EXTENSION vector;
pgvector — embeddings & ANN search
CREATE EXTENSION hstore;
Key/value pairs in a column
CREATE EXTENSION postgres_fdw;
Query remote Postgres servers
CREATE EXTENSION citext;
Case-insensitive text type
SELECT * FROM pg_available_extensions;
List installable extensions
\dx
List installed extensions (psql)

No entry matches “:q”.


About PostgreSQL Cheat Sheet

This PostgreSQL cheat sheet gathers the Postgres you actually type into one searchable reference: psql meta-commands, querying, JSONB, arrays and ranges, CTEs and window functions, upsert and RETURNING, data types, indexes, roles and privileges, maintenance and EXPLAIN, backup and restore, and extensions.

It leans on what makes Postgres different from other databases — the JSONB operators, array and range types, ON CONFLICT upserts with RETURNING, GIN and GiST indexes, and the EXPLAIN ANALYZE output you read when a query is slow — while still covering the everyday SELECT, JOIN and DDL syntax.

The sheet is free and client-side: filter rows live with the search box, hop between sections with the sticky table of contents, copy any statement with one click and print the page as a desk reference.

How to use PostgreSQL Cheat Sheet

  1. Skim the sections, from psql meta-commands and Querying through Indexes to Extensions.
  2. Search for a keyword such as JSONB, ON CONFLICT or EXPLAIN to filter every row live.
  3. Jump to Data types or Indexes when you need storage and performance details rather than syntax.
  4. Click a statement or its copy icon to copy the SQL to your clipboard.
  5. Print the sheet for an offline PostgreSQL reference.

Frequently asked questions

Twelve sections: psql meta-commands, querying, JSONB, arrays and ranges, CTEs and window functions, upsert and RETURNING, data types, indexes, roles and privileges, maintenance and EXPLAIN, backup and restore, and extensions.

Yes. A dedicated section lists the -> and ->> accessors, the @> containment operator, jsonb_set, jsonb_array_elements and the GIN index that makes those queries fast.

They are first on the sheet — \l, \dt, \d, \du, \timing, \x and the other backslash meta-commands you need before writing any SQL.

Yes. Click the SQL snippet or the copy icon on its row and it is copied to your clipboard immediately.

Yes, completely free — searchable, printable and rendered in your browser with no sign-up.


Popular searches
postgresql cheat sheet psql commands postgres jsonb query postgresql data types postgres upsert on conflict postgresql index types postgres sql reference
Need help?
Found an issue with this tool? Let our team know.
Report an issue

Add this free tool to your own website — copy and paste the code below.