Install with Docker
The image includes PostgreSQL, pgvector, postvec and the CLI. The -local tag also includes ONNX Runtime and MiniLM. The volume path follows the official postgres image for that major.
-local: inference in a thread inside PostgreSQL. -remote: inference on postvec-server.
Existing self-hosted cluster: packages. RDS, Aurora, Cloud SQL, Azure, Supabase, Neon: managed PostgreSQL. Tags: downloads.
Local (all-in-one)
docker run -d --name postvec \
-e POSTGRES_PASSWORD_FILE=/run/secrets/postgres-password \
-e POSTGRES_DB=app \
-v postvec-data:/var/lib/postgresql \
-p 127.0.0.1:5432:5432 \
ghcr.io/univec-ai/postvec:0.5.0-2-pg18-localA local demo can pass POSTGRES_PASSWORD=demo instead of a secret file. The example binds the port to loopback.
docker inspect --format '{{.State.Health.Status}}' postvecThe extension exists in POSTGRES_DB only on first initialization of an empty volume. First SQL steps: quick start local.
Optional
docker exec postvec postvec-healthcheck exits 0 when the worker and engine are ready, and names the failing check otherwise. Image attestations: verify artifacts.
Remote image
Prerequisites: postvec-server running (or quick start remote).
Use the -remote tag and point at your postvec-server nodes:
docker run -d --name postvec \
-e POSTGRES_PASSWORD=demo \
-e POSTGRES_DB=app \
-e POSTVEC_GRPC_ENDPOINTS=10.0.0.20:33333 \
-e POSTVEC_HTTP_ENDPOINTS=https://10.0.0.20:22222 \
-v postvec-data:/var/lib/postgresql \
-p 127.0.0.1:5432:5432 \
ghcr.io/univec-ai/postvec:0.5.0-2-pg18-remoteVolume path
| PostgreSQL major | Mount |
|---|---|
| 18 | /var/lib/postgresql |
| 16 or 17 | /var/lib/postgresql/data |
PostgreSQL majors require distinct volumes
Each major needs its own data directory. A major upgrade uses pg_upgrade or dump/restore. An incorrect mount path can create a new empty data directory and conceal existing data. Keep the major and the volume together; retagging an existing volume to another major is unsupported.
Environment
POSTGRES_USER, POSTGRES_DB, POSTVEC_DATABASES, POSTVEC_SHARED_PRELOAD_LIBRARIES, POSTVEC_GRPC_ENDPOINTS and POSTVEC_HTTP_ENDPOINTS accept the _FILE secret form. The file is used when the plain variable is unset. Image-pinned variables and those read by docker exec have no _FILE form.
| Variable | Default | Meaning |
|---|---|---|
POSTVEC_MODE | pinned by the image: grpc in *-remote, embedded in *-local | Inference mode |
POSTVEC_DATABASES | POSTGRES_DB | Comma-separated worker databases |
POSTVEC_GRPC_ENDPOINTS | unset | Remote gRPC |
POSTVEC_HTTP_ENDPOINTS | unset | Remote /config |
POSTVEC_PATH | /opt/postvec | Embedded engine root |
POSTVEC_PROVIDERS_PATH | /etc/postvec/providers.d in *-local, unset in *-remote | Directory postvec provider reads when --path is absent |
POSTVEC_EMBEDDED_MODELS | bundled model | Preload allow-list |
POSTVEC_SHARED_PRELOAD_LIBRARIES | unset | Existing preloads; postvec is appended |
POSTVEC_CREATE_EXTENSION | 1 | 0 skips first-run CREATE EXTENSION |
POSTVEC_HEALTHCHECK_DATABASE | POSTGRES_DB | Database postvec-healthcheck connects to |
POSTVEC_HEALTHCHECK_BEAT_AGE | unset; heartbeat interval + three poll ticks + 2 s | Worker heartbeat budget in seconds |
External providers
To use a hosted embedding API (OpenAI, Cohere, Bedrock, Gemini, Mistral, OpenRouter or UniVec), mount a providers.d directory that holds the API key. Setup: external providers.
docker run -d --name postvec \
-e POSTGRES_PASSWORD=demo \
-e POSTGRES_DB=app \
-e OPENAI_API_KEY \
-v "$PWD/providers.d:/etc/postvec/providers.d:ro" \
-v postvec-data:/var/lib/postgresql \
-p 127.0.0.1:5432:5432 \
ghcr.io/univec-ai/postvec:0.5.0-2-pg18-local| Mount | Contents | Permissions |
|---|---|---|
/etc/postvec/providers.d | One *.toml connector file per provider | Directory 0700, files 0600, owned by the container's postgres uid (999) |
| Any path you reference | The api_key_file a connector points at | 0600, same owner |
Connector files permissions and groups
The host refuses a connector file (or a key file it references) that is readable by other users, so a bind mount has to carry the right mode and owner. With Compose secrets, mount the secret with an explicit mode: 0400 and uid: "999" and reference it as api_key_file. POSTGRES_PASSWORD_FILE and the other PostgreSQL variables use the official entrypoint's _FILE handling; postvec's own are described above. Either way the file has to be readable by the container's postgres uid and by nobody else.
Kubernetes projected secret volumes are symlinks into a ..data directory and are mounted world-readable, so they cannot be referenced as api_key_file. Use api_key_env there.
Per-provider setup: OpenAI, Cohere, Amazon Bedrock, Gemini, Mistral, OpenRouter, UniVec. Conversion entries use the same mount and permissions.
On postvec-server the same files live under the engine root: models on postvec-server.
Adding another database
Init scripts run only on an empty volume.
CREATE DATABASE analytics;
\c analytics
CREATE EXTENSION postvec CASCADE;Include analytics in POSTVEC_DATABASES and recreate the container, or pass -c postvec.database=.... The entrypoint passes this list on the postgres command line, so a new value applies at the next container start.
Diagnose inside the image
The official PostgreSQL image omits pg_lsclusters, so a plain postvec doctor finds no cluster. Pass a socket URL:
docker exec postvec postvec-healthcheckdocker exec -u postgres postvec \
postvec doctor \
--database-url 'postgresql:///app?host=/var/run/postgresql' \
--database appPersistent model storage
Pulled models are stored under the image's engine root. A named volume on /opt/postvec/models copies the bundled MiniLM in. A bind mount or PVC masks the bundled directory, so MiniLM must be copied into the mounted directory.
Tags
Pinned, local: ghcr.io/univec-ai/postvec:0.5.0-2-pg18-local
Pinned, remote: ghcr.io/univec-ai/postvec:0.5.0-2-pg18-remote
Moving, local: ghcr.io/univec-ai/postvec:pg18-local
Moving, remote: ghcr.io/univec-ai/postvec:pg18-remote
Pinned, postvec-server: ghcr.io/univec-ai/postvec-server:0.5.0-2
Moving, postvec-server: ghcr.io/univec-ai/postvec-server:latestEvery database-image tag carries the PostgreSQL major; the moving tags are pgNN-local and pgNN-remote. Pin the versioned tag in production, preferably by digest. The postvec-server image has no PostgreSQL major, so its versioned tag is the release identity and its moving tag is latest. postvec-server explains what runs in that image. A preview tag may not resolve until the release is published.
After you pull a new image, run ALTER EXTENSION on the existing volume. See upgrade.