· Ismaël Mejía (@iemejia)

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:

  1. Build from source. Install build-essential, postgresql-server-dev-17, clone the repos, run make install. Repeat every time you upgrade. Slow, fragile, and bloats your image with compilers you don't need at runtime.
  2. 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.
  3. 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:

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:

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.

github.com/pglayers/pglayers

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.