The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| List available extensions | SELECT name, default_version, installed_version
FROM pg_available_extensions
ORDER BY name; | View examples |
| Inspect installable versions | SELECT version,
installed,
superuser,
trusted,
relocatable
FROM pg_available_extension_versions
WHERE name = 'pgcrypto'; | View examples |
| Create a controlled schema | CREATE SCHEMA extensions AUTHORIZATION extension_owner; | View examples |
| Protect the target schema | REVOKE CREATE ON SCHEMA extensions FROM PUBLIC; | View examples |
| Install a pinned version | CREATE EXTENSION pgcrypto
WITH SCHEMA extensions VERSION '1.3'; | View examples |
| Install only when absent | CREATE EXTENSION IF NOT EXISTS pgcrypto
WITH SCHEMA extensions VERSION '1.3'; | View examples |
| Inspect installed extensions | SELECT extname,
extversion,
extnamespace::regnamespace,
extrelocatable
FROM pg_extension
ORDER BY extname; | View examples |
| Inspect update paths | SELECT source, target, path
FROM pg_extension_update_paths('pgcrypto')
ORDER BY source, target; | View examples |
| Update to a reviewed version | ALTER EXTENSION pgcrypto UPDATE TO '1.3'; | View examples |
| Move a relocatable extension | ALTER EXTENSION pgcrypto SET SCHEMA extensions_v2; | View examples |
| List extension members | SELECT pg_describe_object(d.classid,d.objid,d.objsubid)
FROM pg_depend d
WHERE d.refobjid = (
SELECT oid
FROM pg_extension
WHERE extname='pgcrypto'
); | View examples |
| Attach an existing object | ALTER EXTENSION app_tools ADD FUNCTION app_tools.normalize_email(text); | View examples |
| Drop without cascading | DROP EXTENSION pgcrypto RESTRICT; | View examples |
| Preserve configuration data | SELECT pg_catalog.pg_extension_config_dump('app_tools.settings', 'WHERE NOT built_in'); | View examples |
| Secure an update script path | SELECT pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true); | View examples |
| Pin a function search path | ALTER FUNCTION extensions.secure_length(text)
SET search_path = pg_catalog, pg_temp; | View examples |
A PostgreSQL extension is executable database supply chain: server-side files provide installation and update scripts that create a dependency-tracked set of SQL objects in one database. Safe operation requires more than issuing CREATE EXTENSION. Verify the package and version on every server, install into schemas untrusted roles cannot modify, understand the control file's privilege model, rehearse each update path, and coordinate dumps, failovers, and logical subscribers.
Step by step
Detailed examples
Distinguish server packages from database installations
pg_available_extensions reflects control files reachable by this server, while pg_extension records what is installed in the current database. An extension must be created separately in every database that needs it, and its supporting files must already be present on the server. Compare exact available, default, and installed versions across every primary, standby, image, and recovery environment; a catalog entry alone does not prove that a shared library can be loaded after failover. Benchmark performance-sensitive extensions after every binary or SQL upgrade because planner hooks, operator costs, and native code can change.
SELECT name, default_version, installed_version, comment
FROM pg_catalog.pg_available_extensions
ORDER BY name;
SELECT e.extname, e.extversion,
e.extnamespace::regnamespace AS object_schema,
e.extrelocatable,
pg_get_userbyid(e.extowner) AS extension_owner
FROM pg_catalog.pg_extension AS e
ORDER BY e.extname; Install reviewed code into a schema untrusted roles cannot modify
CREATE EXTENSION runs a package-provided SQL script and tracks its objects as one unit. For a trusted extension, a role with CREATE on the database may install it even when its scripts require elevated privileges; the extension is owned by the caller while protected members are normally owned by the bootstrap superuser. Trusted describes the control-file privilege mechanism, not an independent security audit. Pin the reviewed version, avoid CASCADE unless every dependency and default version is approved, and never expose the target or dependency schemas to untrusted CREATE privileges.
CREATE ROLE extension_owner NOLOGIN;
GRANT CREATE ON DATABASE appdb TO extension_owner;
SET ROLE extension_owner;
CREATE SCHEMA extensions AUTHORIZATION extension_owner;
REVOKE CREATE ON SCHEMA extensions FROM PUBLIC;
-- Verify the packaged version and control metadata before this step.
CREATE EXTENSION pgcrypto
WITH SCHEMA extensions
VERSION '1.3';
RESET ROLE;
REVOKE CREATE ON DATABASE appdb FROM extension_owner; Rehearse the exact update path and its locking behavior
ALTER EXTENSION UPDATE runs one update script or the shortest available chain to the requested version. The scripts execute inside an implicit transaction and therefore cannot contain transaction control or commands such as VACUUM that are forbidden in a transaction block. Atomicity does not imply low impact: scripts can rewrite tables, rebuild indexes, acquire strong locks, invalidate plans, or change result semantics. Test against production-scale data, inspect every intermediate script, set a deliberate maintenance window, and retain a restore-based rollback because downgrade scripts are not guaranteed.
SELECT source, target, path
FROM pg_catalog.pg_extension_update_paths('pgcrypto')
ORDER BY source, target;
BEGIN;
SET LOCAL lock_timeout = '5s';
SET LOCAL statement_timeout = '15min';
ALTER EXTENSION pgcrypto UPDATE TO '1.3';
COMMIT; Preserve the extension dependency boundary
An extension itself has a database-wide unqualified name; extnamespace records the schema containing most or all of its objects, not a namespace containing the extension. Member objects normally cannot be dropped independently. ALTER EXTENSION ADD and DROP change membership without creating or deleting the object and are intended mainly for controlled update scripts. Moving an extension works only when it is relocatable, and dependent extensions can prohibit relocation when their references embed its schema name.
SELECT pg_catalog.pg_describe_object(
d.classid, d.objid, d.objsubid
) AS member, d.deptype
FROM pg_catalog.pg_depend AS d
JOIN pg_catalog.pg_extension AS e
ON e.oid = d.refobjid
WHERE d.refclassid = 'pg_extension'::regclass
AND d.deptype = 'e'
AND e.extname = 'pgcrypto'
ORDER BY member; Package versions and configuration data deliberately
A control file declares the default version, dependencies, privilege requirements, trust, and relocatability; versioned SQL files supply installation and update paths. PostgreSQL can chain update scripts, so test both clean installation and upgrades from every supported starting version. pg_dump normally emits CREATE EXTENSION rather than member definitions and omits member table contents. Mark only genuinely user-maintained configuration rows with pg_extension_config_dump, use stable filters, and avoid circular foreign keys between configuration tables because dump ordering cannot resolve them.
CREATE TABLE app_tools.settings (
setting_name text PRIMARY KEY,
setting_value text NOT NULL,
built_in boolean NOT NULL DEFAULT false
);
SELECT pg_catalog.pg_extension_config_dump(
'app_tools.settings',
'WHERE NOT built_in'
); Defend installation scripts and functions from search-path attacks
Extension installation and update scripts can be subverted when unqualified functions, operators, casts, or relations resolve to hostile objects. Trusted extensions face the highest bar because the installer can select a target schema while the script may execute as the bootstrap superuser. For general-purpose SQL, set a local path of pg_catalog, pg_temp and qualify intended extension objects explicitly. Secure SECURITY DEFINER and other privileged functions with a safe path, exact argument casts, reviewed privileges, and no writable schema before trusted names.
SELECT pg_catalog.set_config(
'search_path',
'pg_catalog, pg_temp',
true
);
-- @extschema@ is substituted with the quoted installation schema.
CREATE FUNCTION @extschema@.secure_length(payload text)
RETURNS integer
LANGUAGE sql
IMMUTABLE
STRICT
SECURITY DEFINER
SET search_path = pg_catalog, pg_temp
RETURN pg_catalog.octet_length(payload);
REVOKE ALL ON FUNCTION @extschema@.secure_length(text) FROM PUBLIC; Coordinate extensions across backups, replicas, and removal
Install matching extension packages before restoring a dump because restore recreates the extension and then loads marked configuration data. Physical replication replays database catalog changes, but shared libraries and control files are host-level assets and must exist on every promotion candidate. Logical replication does not provision extension DDL, so install and update compatible extension versions on subscribers before replicated data or expressions depend on them. Use DROP EXTENSION RESTRICT first, inventory outside dependencies, and expect CASCADE to remove dependent application objects.
WITH members AS (
SELECT d.classid, d.objid, d.objsubid
FROM pg_catalog.pg_depend AS d
JOIN pg_catalog.pg_extension AS e ON e.oid = d.refobjid
WHERE d.refclassid = 'pg_extension'::regclass
AND d.deptype = 'e'
AND e.extname = 'pgcrypto'
)
SELECT pg_catalog.pg_describe_object(
x.classid, x.objid, x.objsubid
) AS dependent_object,
pg_catalog.pg_describe_object(
m.classid, m.objid, m.objsubid
) AS referenced_member,
x.deptype
FROM members AS m
JOIN pg_catalog.pg_depend AS x
ON x.refclassid = m.classid
AND x.refobjid = m.objid
AND x.refobjsubid = m.objsubid
WHERE NOT EXISTS (
SELECT 1 FROM members AS own
WHERE (own.classid, own.objid, own.objsubid) =
(x.classid, x.objid, x.objsubid)
)
ORDER BY dependent_object;
DROP EXTENSION pgcrypto RESTRICT; Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
- PostgreSQL Global Development GroupPostgreSQL: CREATE EXTENSIONpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL: ALTER EXTENSIONpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL: Packaging Related Objects into an Extensionpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL: pg_available_extensionspostgresql.org
- PostgreSQL Global Development GroupPostgreSQL: pg_available_extension_versionspostgresql.org
- PostgreSQL Global Development GroupPostgreSQL: pg_extensionpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL: Logical Replication Restrictionspostgresql.org
- PostgreSQL Global Development GroupPostgreSQL: pg_dumppostgresql.org
- PostgreSQL Global Development GroupPostgreSQL: pgcryptopostgresql.org
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



