Extensions
The Postgres extensions available on CapyDB clusters, how to enable them per database, and why the list is an allowlist.
The allowlist
CapyDB clusters (Postgres 17) provide these extensions:
| Extension | Trusted | What it is for |
|---|---|---|
pg_stat_statements | no | Query statistics; also powers the slow-query view in Observability |
pgcrypto | yes | Cryptographic functions (gen_random_uuid(), digests, PGP) |
uuid-ossp | yes | Legacy UUID generators (uuid_generate_v4() etc.) |
citext | yes | Case-insensitive text type |
hstore | yes | Key/value pairs in a column |
pg_trgm | yes | Trigram matching — fuzzy search and LIKE acceleration |
vector (pgvector) | yes | Vector similarity search for embeddings |
postgis | no | Geographic objects, spatial types, and spatial indexing |
unaccent | yes | Text-search dictionary that strips accents |
ltree | yes | Hierarchical label paths with rich search operators |
fuzzystrmatch | yes | String similarity and distance (soundex, levenshtein) |
btree_gin | yes | GIN operator classes for common scalar types |
btree_gist | yes | GiST operator classes for common scalar types |
plpgsql ships inside every Postgres server and is always available. New projects start with vector, pgcrypto, uuid-ossp, and pg_trgm already enabled.
Trusted vs superuser-managed
The Trusted column is the practical split:
-
Trusted extensions can be enabled by your own database role, on a direct connection, the normal way:
CREATE EXTENSION IF NOT EXISTS pg_trgm; -
Superuser-managed extensions (
postgis,pg_stat_statements) need privileges your role deliberately does not have. Enable them through CapyDB instead — the managed path works for every allowlisted extension, trusted or not, so you can use it uniformly.
Managing extensions per database
Three equivalent surfaces, all backed by the same async job:
Dashboard — the project's Extensions page lists the allowlist with enablement toggles.
CLI:
capydb extensions list --project my-app
capydb extensions enable postgis --project my-app --wait
capydb extensions disable hstore --project my-app --waitAPI:
GET /v1/projects/{projectID}/extensions # allowlist + enabled/trusted/version per extension
POST /v1/projects/{projectID}/extensions # {"name": "postgis"} → 202 + job
DELETE /v1/projects/{projectID}/extensions/{name} # → 202 + jobEnable and disable are asynchronous jobs — poll the returned job (or pass --wait in the CLI) until it reaches completed. The extension is recorded as enabled only after CREATE EXTENSION actually succeeded on the host, so the listing never claims something the database does not have.
Disable is RESTRICT, on purpose
Disabling runs DROP EXTENSION without CASCADE. If anything in your schema depends on the extension — a column of its type, an index using its operator class — the job fails with the dependency error instead of silently dropping your objects. Remove the dependents first if you really mean it.
Why an allowlist
Extensions run inside the database process. A short, audited list keeps upgrades predictable and means a restore or import never lands on a host missing a library it needs. The list covers the unexciting majority of real workloads: UUIDs, crypto, fuzzy search, embeddings, and — since PostGIS joined — geospatial.
Imports and extensions
The import preflight fails when the source database uses an extension that is not on this list, naming the offenders. Options at that point:
- drop the extension on (a copy of) the source if it was installed but unused — common with provider-default extensions
- replace its usage (
uuid-ossp→pgcrypto'sgen_random_uuid()is the classic) - if your workload genuinely needs something missing, contact support — the allowlist grows on demand, not on speculation
After a successful import, the per-project extension list is reconciled with what the restored dump actually created, so the Extensions page reflects reality rather than the pre-import defaults.