PostgreSQL Extensions Management for Self-Hosted Supabase

Learn how to install, enable, and manage PostgreSQL extensions in self-hosted Supabase to unlock 450+ extensions beyond cloud limits.

Cover Image for PostgreSQL Extensions Management for Self-Hosted Supabase

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:

EnvironmentAvailable ExtensionsCustom Extensions
Supabase Cloud~64 pre-approvedLimited via pg_tle
Self-Hosted450+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_partman added to address partitioning needs
  • Improved pg_stat_statements performance

If your application depends on deprecated extensions, you have options:

  1. Stay on Postgres 15: Supported until approximately May 2026
  2. Migrate functionality: Replace plv8 with Edge Functions or pg/plpgsql
  3. 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 LevelExtension TypeExample
LowPure SQL/PL/pgSQLpg_trgm, uuid-ossp
MediumTrusted Languagepg_tle extensions
HighC ExtensionsCustom compiled extensions
CriticalSuperuser Requiredpg_cron (job scheduler)

Security Best Practices

  1. Review source code before installing unfamiliar extensions
  2. Limit extension schemas to restrict access:
    CREATE SCHEMA extensions;
    CREATE EXTENSION vector SCHEMA extensions;
    GRANT USAGE ON SCHEMA extensions TO authenticated;
    
  3. Use separate roles for administrative extensions
  4. Audit extension changes using pgaudit

Common Extension Use Cases

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