Sign inSign up

lcdss/postgres

By lcdss

•Updated about 17 hours ago

PostgreSQL images with pgx_ulid and pgvector preinstalled

Image
0

6.6K

lcdss/postgres repository overview

⁠postgres

Docker Pulls Image Size Daily Sync

lcdss/postgres is the official PostgreSQL Docker image with extensions already built in, so you get them without compiling anything:

  • pgx_ulid⁠ — a native ulid column type and gen_ulid()
  • pgvector⁠ — the vector type with HNSW and IVFFlat indexes

If you already use the official Postgres image, this one behaves the same way. The only difference is that those extensions are available inside the database.

⁠Supported Platforms

linux/amd64 only. Upstream postgres publishes more architectures, but these images do not, so on Apple Silicon and other arm64 hosts Docker falls back to emulation.

⁠Quick Start

docker run -d \
  --name postgres \
  -e POSTGRES_PASSWORD=postgres \
  -p 5432:5432 \
  lcdss/postgres:18-alpine
docker exec -it postgres psql -U postgres
CREATE EXTENSION pgx_ulid;
CREATE EXTENSION vector;

CREATE TABLE users (
  id ulid PRIMARY KEY DEFAULT gen_ulid(),
  email text NOT NULL UNIQUE,
  embedding vector(3),
  created_at timestamptz NOT NULL DEFAULT now()
);

INSERT INTO users (email, embedding)
VALUES ('[email protected]', '[1,2,3]')
RETURNING id;

CREATE INDEX ON users USING hnsw (embedding vector_l2_ops);

SELECT id FROM users ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
⁠docker compose
services:
  postgres:
    image: lcdss/postgres:18-alpine
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_USER: postgres
      POSTGRES_DB: app
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/18/docker

volumes:
  pgdata:

Postgres 18 images store data under /var/lib/postgresql/18/docker; older majors use /var/lib/postgresql/data. Match whatever the tag you pin uses.

⁠Enabling The Extensions

The image ships the extension files and enables nothing. Run CREATE EXTENSION in each database that needs one, exactly as you would on the official image:

CREATE EXTENSION IF NOT EXISTS pgx_ulid;
CREATE EXTENSION IF NOT EXISTS vector;

To see what is available and what is installed:

SELECT name, default_version FROM pg_available_extensions;
SELECT extname, extversion FROM pg_extension;

If you would rather have them created for you, POSTGRES_ENABLE_EXTENSIONS runs CREATE EXTENSION on first startup, in postgres, template1, and POSTGRES_DB:

docker run -e POSTGRES_ENABLE_EXTENSIONS="pgx_ulid vector" ...

That reaches template1, so every database created afterwards inherits those extensions and pg_dump of them emits CREATE EXTENSION, which only restores where the extension exists. Leave it unset if your dumps have to restore on a stock image. Like every initialization script, it runs on a fresh data directory only.

⁠Monotonic ULIDs

gen_monotonic_ulid() needs the library preloaded, which the image does not do by default, and it only works on a tag that carries pgx_ulid:

docker run -d \
  --name postgres-monotonic \
  -e POSTGRES_PASSWORD=postgres \
  lcdss/postgres:18-alpine \
  postgres -c shared_preload_libraries=pgx_ulid
CREATE EXTENSION IF NOT EXISTS pgx_ulid;
SELECT gen_monotonic_ulid();

In compose, pass the same override as command:.

⁠Vector Indexes

Building an HNSW index on a large table wants more memory than the Docker default shared memory size, so raise it when you hit could not resize shared memory segment:

docker run --shm-size=1g ...

⁠Configuration

Everything the official image supports applies here unchanged: the POSTGRES_* variables, PGDATA, POSTGRES_INITDB_ARGS, scripts dropped into /docker-entrypoint-initdb.d, the data volume layout, and the entrypoint behavior. See https://hub.docker.com/_/postgres⁠ for that reference.

⁠Tags

Tags mirror the official postgres image:

  • Exact major tags from 14 and newer
  • The alpine and trixie image families
  • The floating alpine and trixie tags, which move with the newest major

A plain tag carries every extension. A suffixed tag carries exactly one:

TagContents
18-alpine, 18-trixie, alpine, trixiepgx_ulid + vector
18-alpine-ulid, alpine-ulid, …pgx_ulid only
18-alpine-vector, alpine-vector, …vector only

The live list is at https://hub.docker.com/r/lcdss/postgres/tags⁠.

A scheduled job checks upstream daily and rebuilds a tag when the upstream digest or the build inputs change, so pinning a floating tag means the underlying major can change under you. Pin an exact major, or a digest, when that matters.

Each image records where it came from, which you can inspect before trusting a mirror:

docker image inspect lcdss/postgres:18-alpine \
  --format '{{ json .Config.Labels }}'
  • org.opencontainers.image.base.name — the upstream tag it was built from
  • io.github.lcdss.postgres.source-digest — the upstream manifest digest
  • io.github.lcdss.postgres.build-signature — the build inputs used
  • io.github.lcdss.postgres.variant — which extension set the tag carries
  • io.github.lcdss.postgres.extensions — each bundled extension and its ref

⁠Migrating From lcdss/postgres-ulid

lcdss/postgres-ulid keeps being published and carries the same pgx_ulid only content as before, so nothing breaks if you stay. New extensions land here instead, so move when you want them:

-image: lcdss/postgres-ulid:18-alpine
+image: lcdss/postgres:18-alpine-ulid   # same contents
+image: lcdss/postgres:18-alpine        # also pgvector

Two things changed for everyone, on both repositories:

  • pgx_ulid is no longer created for you. Older images ran CREATE EXTENSION pgx_ulid on a fresh data directory; these do not. Run it yourself, or start the container with POSTGRES_ENABLE_EXTENSIONS=pgx_ulid to keep the old behavior. Existing data directories are unaffected — the extension is already there.
  • The image labels moved from io.github.lcdss.postgres-ulid.* to io.github.lcdss.postgres.*, and the entrypoint init script is now 10-enable-extensions.sh.

⁠What This Image Changes

Each extension is compiled once per Postgres major and image family, published as a standalone artifact, and copied into the mirrored image, along with one initialization script that stays inert unless POSTGRES_ENABLE_EXTENSIONS is set. Nothing else about the official image is modified: same entrypoint, same defaults, no extensions created, no preloaded libraries.

Every extension is pinned to a known revision, listed in extensions.json⁠ and recorded on each image in the io.github.lcdss.postgres.extensions label.

⁠Contributing

Build, test, and automation details live in CONTRIBUTING.md⁠.

⁠License

This repository's own files are MIT licensed, see LICENSE⁠. The images also carry everything upstream ships: PostgreSQL under the PostgreSQL License⁠, the base image contents under their respective licenses, and each bundled extension under its own terms (pgx_ulid⁠, pgvector⁠).

⁠Disclaimer

Unofficial image, not affiliated with Docker, Inc., the PostgreSQL Global Development Group, or the maintainers of the bundled extensions.

Tag summary

Content type

Image

Digest

sha256:b7014943d…

Size

111 MB

Last updated

about 17 hours ago

docker pull lcdss/postgres:16-alpine-ulid