One of the most compelling reasons to self-host Supabase is the freedom to customize your PostgreSQL database with any extension you need. While Supabase Cloud limits you to roughly 64 pre-approved extensions, a self-hosted instance can access over 450 extensions—everything from advanced analytics to specialized data types. This guide walks through managing PostgreSQL extensions in your self-hosted Supabase deployment.
Why Extensions Matter for Self-Hosted Supabase
PostgreSQL extensions are the secret weapon that transforms Postgres from a relational database into a swiss army knife. They add functionality—vector search, geospatial queries, time-series compression, graph relationships—without modifying the core database engine.
The gap between cloud and self-hosted extension availability is significant:
| Environment | Available Extensions | Custom Extensions |
|---|---|---|
| Supabase Cloud | ~64 pre-approved | Limited via pg_tle |
| Self-Hosted | 450+ | Full filesystem access |
For teams building AI applications, location-based services, or systems requiring specialized data types, this flexibility alone can justify the effort of self-hosting.
Pre-Installed Extensions in Supabase Postgres
Supabase Postgres ships as a batteries-included distribution with carefully selected extensions already compiled and ready to enable. Before installing anything custom, check what's already available:
-- List all installed extensions SELECT * FROM pg_available_extensions ORDER BY name; -- Check currently enabled extensions SELECT extname, extversion FROM pg_extension;
Core Extensions Worth Enabling
Most self-hosted installations benefit from enabling these extensions immediately:
-- Vector similarity search for AI/ML applications CREATE EXTENSION IF NOT EXISTS vector; -- Full-text search improvements CREATE EXTENSION IF NOT EXISTS pg_trgm; -- UUID generation CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- JSON schema validation CREATE EXTENSION IF NOT EXISTS pg_jsonschema; -- Scheduled jobs (if using pg_cron) CREATE EXTENSION IF NOT EXISTS pg_cron;
You can enable extensions through Supabase Studio's SQL Editor or directly via psql. For a list of extensions commonly used with Supabase, see the official extensions documentation.
Installing Custom Extensions
Self-hosting unlocks the ability to add extensions not included in the default Supabase Postgres image. The process depends on your deployment approach.
Method 1: Using pg_tle (Trusted Language Extensions)
The cleanest approach for compatible extensions uses pg_tle, which allows installing extensions without filesystem access:
-- Enable pg_tle first CREATE EXTENSION IF NOT EXISTS pg_tle; -- Install from database.dev (Supabase's extension registry) SELECT pgtle.install_extension_if_not_exists( 'your_extension_name', '1.0.0', 'Description of the extension' );
The database.dev registry hosts community extensions that work with pg_tle. This method works on both cloud and self-hosted, making migrations between environments easier.
Method 2: Custom Docker Image
For extensions requiring compiled C code or filesystem access, build a custom Postgres image:
# Dockerfile.custom-postgres
FROM supabase/postgres:17.2.3
# Install build dependencies
USER root
RUN apt-get update && apt-get install -y \
build-essential \
postgresql-server-dev-17 \
git
# Clone and build your extension
RUN git clone https://github.com/example/pg_custom_extension.git \
&& cd pg_custom_extension \
&& make \
&& make install
# Clean up
RUN apt-get remove -y build-essential git \
&& apt-get autoremove -y \
&& rm -rf /var/lib/apt/lists/*
USER postgres
Update your Docker Compose configuration to use the custom image:
services:
db:
image: your-registry/supabase-postgres-custom:17.2.3
# ... rest of configuration
Method 3: Volume-Mounted Extensions
For quick testing without rebuilding images, mount compiled extensions:
services:
db:
volumes:
- ./custom-extensions:/usr/share/postgresql/17/extension
This approach is useful for development but not recommended for production due to portability concerns.
Managing Extension Versions
Extension version management becomes critical as your database grows. Track versions and plan upgrades carefully.
Checking Current Versions
-- View all extensions with versions SELECT e.extname, e.extversion, n.nspname as schema FROM pg_extension e JOIN pg_namespace n ON e.extnamespace = n.oid ORDER BY e.extname;
Upgrading Extensions
Most extensions support in-place upgrades:
-- Upgrade to latest available version ALTER EXTENSION vector UPDATE; -- Upgrade to specific version ALTER EXTENSION pg_graphql UPDATE TO '1.5.0';
Before upgrading in production, test the upgrade path on a staging environment. Some extensions—particularly those with significant schema changes—may require migration steps. If you're using database branching, create a branch to test the upgrade safely.
PostgreSQL 17 Extension Compatibility
The transition from PostgreSQL 15 to 17 has impacted extension availability. Key changes to be aware of:
Deprecated in Postgres 17:
plv8(JavaScript procedural language)timescaledb(time-series database)
New in Postgres 17:
pg_partmanadded to address partitioning needs- Improved
pg_stat_statementsperformance
If your application depends on deprecated extensions, you have options:
- Stay on Postgres 15: Supported until approximately May 2026
- Migrate functionality: Replace plv8 with Edge Functions or pg/plpgsql
- Build custom image: Include TimescaleDB in your own Postgres 17 image
For upgrade guidance, see our version migration guide.
Extension Dependencies and Load Order
Some extensions depend on others or require specific load order configuration. Handle this in your postgresql.conf:
# Extensions that must be preloaded shared_preload_libraries = 'pg_cron,pg_stat_statements,pgaudit,pg_net' # pg_cron specific configuration cron.database_name = 'postgres'
When using Docker Compose, set these via environment variables:
services:
db:
environment:
POSTGRES_INITDB_ARGS: "--data-checksums"
command: >
postgres
-c shared_preload_libraries=pg_cron,pg_stat_statements
-c cron.database_name=postgres
Monitoring Extension Performance
Extensions can impact database performance. Monitor their behavior:
-- Check extension-specific statistics (pg_stat_statements example) SELECT query, calls, total_exec_time, mean_exec_time, rows FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 20; -- Monitor pg_cron job execution SELECT * FROM cron.job_run_details ORDER BY start_time DESC LIMIT 10;
For comprehensive database monitoring, see our observability guide.
Extension Security Considerations
Not all extensions are created equal from a security perspective. Evaluate carefully before enabling:
Risk Categories
| Risk Level | Extension Type | Example |
|---|---|---|
| Low | Pure SQL/PL/pgSQL | pg_trgm, uuid-ossp |
| Medium | Trusted Language | pg_tle extensions |
| High | C Extensions | Custom compiled extensions |
| Critical | Superuser Required | pg_cron (job scheduler) |
Security Best Practices
- Review source code before installing unfamiliar extensions
- Limit extension schemas to restrict access:
CREATE SCHEMA extensions; CREATE EXTENSION vector SCHEMA extensions; GRANT USAGE ON SCHEMA extensions TO authenticated;
- Use separate roles for administrative extensions
- Audit extension changes using pgaudit
Common Extension Use Cases
AI and Vector Search
The pgvector extension enables semantic search and RAG applications:
CREATE EXTENSION vector; CREATE TABLE documents ( id SERIAL PRIMARY KEY, content TEXT, embedding vector(1536) ); CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
Geospatial Data
PostGIS transforms Postgres into a spatial database. See our PostGIS setup guide for details.
Background Processing
pg_cron and PGMQ enable server-side job scheduling and message queues without external infrastructure.
Troubleshooting Extension Issues
Extension Won't Load
-- Check if extension files exist SELECT * FROM pg_available_extensions WHERE name = 'your_extension'; -- Verify shared_preload_libraries if required SHOW shared_preload_libraries;
Version Conflicts
-- Check default version vs installed SELECT name, default_version, installed_version FROM pg_available_extensions WHERE installed_version IS NOT NULL AND default_version != installed_version;
Permission Denied
Extensions requiring superuser privileges fail with standard roles. Use the postgres superuser or grant specific privileges:
-- Grant extension creation to a role ALTER ROLE your_role CREATEDB; -- Or run extension creation as superuser
Managing Extensions with Supascale
While Supascale focuses on deployment, backup, and domain management rather than direct extension management, the backup system captures your extension configurations. When you restore from a backup, all enabled extensions and their configurations are preserved.
For teams managing multiple Supabase instances, Supascale's one-time purchase model means you can experiment with extensions across unlimited projects without per-project costs adding up.
Further Reading
- PostgreSQL Extensions Overview - Official Supabase documentation
- Setting Up pgvector for AI Applications
- Docker Compose Production Best Practices
- Backup and Restore Guide
