| name | postgres-extensions |
| description | PostgreSQL extension management and the bundled `contrib` catalog. Use when running `CREATE EXTENSION` / `ALTER EXTENSION ... UPDATE` / `DROP EXTENSION`, listing extensions (`\dx`, `pg_available_extensions`), or choosing which contrib module enables a feature — FDWs (`postgres_fdw`, `dblink`, `file_fdw`), trigram/fuzzy search (`pg_trgm`, `fuzzystrmatch`), crypto/UUIDs (`pgcrypto`, `gen_random_uuid`), types `hstore`/`ltree`/`citext`/`cube`, query stats (`pg_stat_statements`, `auto_explain`), index helpers (`btree_gin`, `btree_gist`, `bloom`), or storage forensics (`pageinspect`, `amcheck`, `pg_surgery`). Also covers trusted (non-superuser) extensions, `shared_preload_libraries`, and `CASCADE`. Disambiguation — extension management plus the contrib catalog; use psql for the client, postgres-sql for core SQL, postgres-performance for tuning *with* these extensions, postgres-admin for server config. Version notes are inline `(pgNN+)`; bedrock modules are unannotated, see references/version-features.md. |
PostgreSQL Extensions & the contrib Catalog
Overview
A PostgreSQL extension is a packaged bundle of SQL objects — functions, data
types, operators, index access methods, casts, even C libraries — that you install
into a database with a single CREATE EXTENSION command and remove just as cleanly
with DROP EXTENSION. PostgreSQL tracks every object an extension owns, so the whole
unit can be upgraded, relocated to another schema, or dumped/restored atomically.
contrib is the set of extensions and modules that ship in the PostgreSQL source
tree itself (under contrib/) and are packaged by most distributions as a
postgresql-contrib package. They are official, versioned with the server, and
maintained by the core project — but not installed into a database until you ask.
This skill is the map of that ecosystem plus the commands to manage it.
Key mental model:
- An extension is a managed unit, not loose SQL.
CREATE EXTENSION pg_trgm; is not
the same as running its SQL by hand — Postgres records membership in pg_extension
so DROP/ALTER ... UPDATE work.
contrib ships with the server but is dormant. The files live on disk (often a
separate OS package); CREATE EXTENSION activates one per database.
- Two version numbers, do not conflate them. The extension's own version (e.g.
pg_stat_statements 1.13, from its .control default_version) is independent of
the PostgreSQL release (e.g. 18). See Two version numbers.
- Some extensions need a server restart, because they hook into the backend via
shared_preload_libraries (e.g. pg_stat_statements, auto_explain). Most don't.
Disambiguation. This skill = extension management + the bundled contrib
catalog. For the psql client (\dx, meta-commands) use the psql skill;
for core SQL / dialect use postgres-sql; for using perf extensions to
actually tune queries use postgres-performance (this skill only points at
them); for server configuration like editing shared_preload_libraries or
postgresql.conf use postgres-admin. External extensions (PostGIS, pgvector,
TimescaleDB) are not in contrib — see External extensions.
Version annotations
This skill targets the contrib set shipped with PostgreSQL 18 (stable), with notes
for 19 (beta). Inline (pgNN+) marks the first PostgreSQL release a module or
feature shipped in. Modules present since the old 9.x era are "bedrock" and carry no
tag (e.g. pgcrypto, pg_trgm, hstore, pg_stat_statements). A tag means
"requires PostgreSQL NN or newer." The full feature → minimum-version map with sources
is in references/version-features.md. Always confirm
against the running server (SELECT version();).
When to use which approach
| You want to… | Use |
|---|
| Turn on a packaged feature in a database | CREATE EXTENSION name; |
| See what's installed vs. available | \dx · pg_available_extensions |
| Upgrade an extension's objects after a server upgrade | ALTER EXTENSION name UPDATE; |
| Remove an extension and everything it owns | DROP EXTENSION name CASCADE; |
| Pull in dependencies automatically | CREATE EXTENSION name CASCADE; |
| Let a non-superuser install a safe extension | a trusted extension (pg13+) |
| Enable a backend hook (stats, logging) | add to shared_preload_libraries + restart |
Managing extensions
Install
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE EXTENSION hstore WITH SCHEMA extensions;
CREATE EXTENSION earthdistance CASCADE;
CREATE EXTENSION pg_stat_statements VERSION '1.13';
IF NOT EXISTS makes it safe to re-run in migrations.
WITH SCHEMA s installs the objects into schema s (the schema must exist, or use
CASCADE to create it for a relocatable extension). This matters for search_path:
if you install pg_trgm into a schema not on the path, you must schema-qualify its
operators/functions or add the schema to search_path.
CASCADE (pg9.6+) auto-installs required extensions and creates a missing target
schema. Great for earthdistance (needs cube).
VERSION 'x.y' installs a specific version if multiple are available on disk.
Discover
\dx
\dx+ pg_trgm
SELECT * FROM pg_available_extensions;
SELECT * FROM pg_available_extension_versions;
SELECT extname, extversion FROM pg_extension;
pg_available_extensions.default_version is what CREATE EXTENSION installs if you
don't pin a version; installed_version is NULL until you create it. (pg19+ adds a
location column reporting the on-disk directory.)
Upgrade
ALTER EXTENSION pg_stat_statements UPDATE;
ALTER EXTENSION postgres_fdw UPDATE TO '1.2';
Run ALTER EXTENSION ... UPDATE after a major PostgreSQL upgrade (or after
installing a newer contrib package) to apply the extension's upgrade scripts — a
pg_upgrade migrates data but does not bump extension versions for you. Check for
stragglers:
SELECT name, default_version, installed_version
FROM pg_available_extensions
WHERE installed_version IS DISTINCT FROM default_version
AND installed_version IS NOT NULL;
Relocate / modify / remove
ALTER EXTENSION hstore SET SCHEMA extensions;
DROP EXTENSION IF EXISTS hstore;
DROP EXTENSION hstore CASCADE;
CASCADE on DROP removes everything that depends on the extension (columns of its
types, indexes using its operator classes, …) — powerful and destructive. Prefer the
non-cascade form first to see what would break.
Two version numbers
| Number | Example | Where it comes from | Meaning |
|---|
| PostgreSQL release | 18, 19beta1 | SELECT version(); / server_version | The database server version |
| Extension version | pg_stat_statements 1.13 | the module's .control default_version | The extension's own object/schema version |
These move independently. pg_stat_statements being version 1.13 says nothing about
which PostgreSQL release you run — it's the extension's internal version, bumped by its
own upgrade scripts (pg_stat_statements--1.12--1.13.sql). In this skill, (pgNN+) tags
always mean the PostgreSQL release, never the extension's own number.
Trusted extensions (pg13+)
By default CREATE EXTENSION requires superuser. A trusted extension can instead be
installed by any role with CREATE privilege on the database — these are the modules
that "cannot provide access to outside-the-database functionality." The contrib
extensions trusted in a default install are:
btree_gin, btree_gist, citext, cube, dict_int, fuzzystrmatch, hstore,
intarray, isn, lo, ltree, pgcrypto, pg_trgm, seg, tablefunc, tcn,
tsm_system_rows, tsm_system_time, unaccent, uuid-ossp (plus the PL transforms
like bool_plperl, jsonb_plperl).
Notably not trusted: postgres_fdw, dblink, file_fdw, pg_stat_statements,
adminpack, and the forensic/inspection modules — they reach outside the database or
need superuser.
Extensions that need shared_preload_libraries (restart required)
A few modules hook into the backend at startup and must be listed in
shared_preload_libraries in postgresql.conf, then the server restarted:
| Module | Why preload |
|---|
pg_stat_statements | accumulates per-query stats in shared memory |
auto_explain | hooks executor end to log plans (can also LOAD per session) |
pg_prewarm | only the autoprewarm background worker needs preload (pg11+); the pg_prewarm() function does not |
passwordcheck, auth_delay, sepgsql, basic_archive, basebackup_to_shell | server-side hooks/policies |
After preloading, you still run CREATE EXTENSION pg_stat_statements; to get the SQL
views. For editing shared_preload_libraries and other server config, see the
postgres-admin skill. auto_explain and pg_overexplain (pg18+) can alternatively be
loaded for one session with LOAD 'auto_explain';.
The contrib catalog — highlights
One-liners and the most-used snippets. The full catalog of every bundled module —
grouped, with usage examples and version notes — is in
references/contrib-catalog.md.
Text, fuzzy & full-text search
CREATE EXTENSION pg_trgm;
SELECT similarity('postgres', 'postgers');
CREATE INDEX ON docs USING gin (body gin_trgm_ops);
CREATE EXTENSION fuzzystrmatch;
SELECT levenshtein('kitten','sitting'), soundex('Robert');
CREATE EXTENSION unaccent;
SELECT unaccent('café');
Useful data types
CREATE EXTENSION citext;
CREATE EXTENSION hstore;
CREATE EXTENSION ltree;
CREATE EXTENSION cube;
CREATE EXTENSION isn;
SELECT 'a=>1'::hstore -> 'a';
Foreign data & external access
CREATE EXTENSION postgres_fdw;
CREATE SERVER remote FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'db2', dbname 'app');
CREATE USER MAPPING FOR CURRENT_USER SERVER remote OPTIONS (user 'app', password '...');
IMPORT FOREIGN SCHEMA public FROM SERVER remote INTO remote_public;
CREATE EXTENSION file_fdw;
CREATE EXTENSION dblink;
Crypto & UUIDs
CREATE EXTENSION pgcrypto;
SELECT crypt('secret', gen_salt('bf'));
SELECT gen_random_uuid();
CREATE EXTENSION "uuid-ossp";
Query statistics & plan logging (point to postgres-performance for tuning)
CREATE EXTENSION pg_stat_statements;
SELECT query, calls, total_exec_time FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5;
LOAD 'auto_explain';
SET auto_explain.log_min_duration = '500ms';
These are diagnostic plumbing. For how to interpret and act on them to tune queries,
use the postgres-performance skill.
Indexing helpers
CREATE EXTENSION btree_gist;
CREATE EXTENSION btree_gin;
CREATE EXTENSION bloom;
Table functions & misc
CREATE EXTENSION tablefunc;
CREATE EXTENSION earthdistance CASCADE;
Storage inspection & forensics (mostly superuser)
CREATE EXTENSION pageinspect;
CREATE EXTENSION pg_buffercache;
CREATE EXTENSION pgstattuple;
CREATE EXTENSION pg_visibility;
CREATE EXTENSION amcheck;
CREATE EXTENSION pg_surgery;
CREATE EXTENSION pg_walinspect;
CREATE EXTENSION pg_freespacemap;
CREATE EXTENSION pg_prewarm;
CREATE EXTENSION pg_logicalinspect;
LOAD 'pg_overexplain';
External (not in contrib)
These ubiquitous extensions are not bundled — install them separately from their own
projects/packages:
- PostGIS — full geospatial (geometry/geography, spatial indexing). For simple
great-circle distance only, contrib
earthdistance may suffice.
- pgvector —
vector type + ANN indexes for embeddings/similarity search.
- TimescaleDB — time-series hypertables, continuous aggregates.
After installing the OS package/build, they still activate via CREATE EXTENSION postgis;
etc. — the management commands above are identical.
Troubleshooting
ERROR: could not open extension control file ".../name.control": No such file —
the extension's files aren't installed on the server. Install the OS package (e.g.
postgresql-contrib, or postgresql18-contrib) or build it; CREATE EXTENSION only
registers files that already exist on disk.
ERROR: permission denied to create extension "X" — Hint: Must have CREATE privilege ... or be superuser — it's not a trusted extension (or you lack CREATE on the DB).
See Trusted extensions. Use a superuser, or pick a trusted
alternative.
ERROR: required extension "cube" is not installed — install the dependency first,
or use CREATE EXTENSION earthdistance CASCADE;.
pg_stat_statements view is empty / "must be loaded via shared_preload_libraries" —
it wasn't preloaded. Add it to shared_preload_libraries, restart, then
CREATE EXTENSION. (postgres-admin covers the config edit.)
- Functions "do not exist" after install — the extension was installed
WITH SCHEMA
a schema not on your search_path. Schema-qualify the call or add the schema to
search_path.
- A function/option errors on an older server — it may be newer than your release.
Check
SELECT version(); and the (pgNN+) tag / references/version-features.md.
DROP EXTENSION fails with dependency errors — other objects use its types/operators.
Inspect with \dx+ name, then drop dependents or use CASCADE (destructive).
- Confusing two version numbers —
default_version in a .control file is the
extension's version, not the PostgreSQL release. See Two version numbers.
References
- references/management.md — exhaustive
CREATE/ALTER/DROP EXTENSION grammar, the .control/SQL upgrade-script file model, the system catalogs
& views, relocatable schemas, dump/restore behavior, trusted-extension mechanics, and
the shared_preload_libraries restart matrix.
- references/contrib-catalog.md — the complete catalog of
every bundled
contrib module, grouped by category, each with purpose, CREATE EXTENSION snippet, a tiny usage example, and version notes.
- references/version-features.md — extension/feature →
minimum PostgreSQL version, the "how to read it" guide (incl. the
default_version ≠
PG-release distinction), the bedrock policy, and sources.
Resources