Introducing pglayers
The official PostgreSQL Docker images are great -- they're well-maintained, secure, and reliable. But they ship with almost no extensions. If you need pgvector for AI embeddings, PostGIS for geospatial queries, or pg_cron for scheduled jobs, you're on your own: installing compilers, resolving dependencies, building from source, or trusting a third-party image that bundles a fixed set you can't change.
pglayers fixes this. It gives you 50+ pre-built PostgreSQL extensions as stackable Docker image layers. You add one line per extension to your Dockerfile -- no compilation, no package managers, no build tools.
The problem
Suppose you want PostgreSQL with pgvector and pg_cron. Today your options are:
- Build from source. Install
build-essential,postgresql-server-dev-17, clone the repos, runmake install. Repeat every time you upgrade. Slow, fragile, and bloats your image with compilers you don't need at runtime. - Use a third-party image. Someone else built an image with a particular set of extensions. Maybe it includes what you need, maybe it doesn't. You lose control over the base image, update schedule, and security patches.
- PGDG packages. Install from
apt.postgresql.org. Works, but the package manager pulls transitive dependencies, and you're mixing package management with Docker layer caching in ways that complicate reproducibility.
None of these compose well. If you need pgvector and PostGIS and TimescaleDB and pg_cron, each approach compounds its complexity.
How pglayers works
Each extension is published as a minimal Docker image (built FROM scratch)
containing only the extension's compiled binaries: the .so shared
library, the .control file, and the SQL migration scripts. These
files are laid out at exactly the paths PostgreSQL expects:
/usr/lib/postgresql/17/lib/vector.so
/usr/share/postgresql/17/extension/vector.control
/usr/share/postgresql/17/extension/vector--0.8.3.sql
To use them, you write a standard multi-stage COPY --from in your
Dockerfile:
FROM postgres:17
COPY --from=ghcr.io/pglayers/pgx-pgvector:17 / /
COPY --from=ghcr.io/pglayers/pgx-pg_cron:17 / /
COPY --from=ghcr.io/pglayers/pgx-postgis:17 / /
That's it. Docker pulls the pre-built layers from the registry and overlays them onto the official image. No compilation happens at build time -- it's just file copies. The result is a single image with exactly the extensions you chose.
Then you can CREATE EXTENSION as usual:
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pg_cron;
CREATE EXTENSION IF NOT EXISTS postgis;
Ready-to-use profile images
If you don't want to pick individual extensions, pglayers provides pre-built combined images called profiles:
# All 50+ extensions, pre-configured
docker run -d -e POSTGRES_PASSWORD=secret ghcr.io/pglayers/pglayers-full:17
# Extensions matching Azure Database for PostgreSQL
docker run -d -e POSTGRES_PASSWORD=secret ghcr.io/pglayers/pglayers-azure:17
Profile images come with shared_preload_libraries already
configured, companion processes started (like pg_lake's DuckDB backend),
and all the GUC settings extensions need. Just docker run and
you have a fully-loaded PostgreSQL instance.
The azure profile also includes DocumentDB, which provides MongoDB wire protocol compatibility on port 10260. MongoDB clients (mongosh, pymongo, the Node.js driver) connect directly -- same engine as Azure DocumentDB.
What's included
pglayers ships 53 extensions across PostgreSQL 17, 18, and 19. A few highlights:
- pgvector + pgvectorscale -- vector similarity search for AI/ML embeddings, with high-performance DiskANN indexing
- PostGIS + pgRouting -- the full geospatial stack (geometry, geography, raster, routing)
- TimescaleDB -- hypertables, compression, and continuous aggregates for time-series data
- pg_cron -- cron-like job scheduler running inside the database
- DocumentDB -- MongoDB-compatible document engine with wire protocol support
- pg_lake -- query Iceberg tables and data lake files (Parquet, CSV, JSON) directly from PostgreSQL
- pg_duckdb -- DuckDB's columnar analytics engine embedded in Postgres for OLAP workloads
- Apache AGE -- graph database with openCypher query support
All images are multi-architecture (linux/amd64 and linux/arm64), so Docker automatically pulls the right binary for your platform -- whether you're on an M-series Mac or an x86 CI runner.
Quality guarantees
Every extension goes through a CI pipeline that checks:
- No file collisions -- extension pairs are compared to ensure they don't overwrite each other's files
- No base image overwrites -- extensions never replace files from the official postgres image
- Shared library resolution --
lddverifies all transitive dependencies are present - CREATE EXTENSION -- every extension loads successfully
- Functional smoke tests -- each extension is exercised with real queries, not just loaded
Getting started
The fastest way to try pglayers is the full profile image:
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=secret \
ghcr.io/pglayers/pglayers-full:17
Then connect and enable any extension:
psql -h localhost -U postgres
CREATE EXTENSION vector;
CREATE EXTENSION postgis;
SELECT '[1,2,3]'::vector <-> '[4,5,6]'::vector AS distance;
To build a custom image with only the extensions you need, create a Dockerfile:
FROM postgres:17
COPY --from=ghcr.io/pglayers/pgx-pgvector:17 / /
COPY --from=ghcr.io/pglayers/pgx-timescaledb:17 / /
COPY --from=ghcr.io/pglayers/pgx-pg_cron:17 / /
RUN echo "shared_preload_libraries = 'timescaledb,pg_cron'" \
>> /usr/share/postgresql/postgresql.conf.sample
Build and run:
docker build -t my-postgres .
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=secret my-postgres
Open source
pglayers is MIT licensed and hosted on GitHub. The project welcomes contributions -- whether that's adding a new extension, improving tests, or reporting issues.
pglayers stands on the shoulders of the PostgreSQL community: the PostgreSQL Global Development Group, the PGDG APT repository maintainers, the official Docker image maintainers, and every extension author who releases their work under permissive open-source licenses.