Skip to content

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-local

A local demo can pass POSTGRES_PASSWORD=demo instead of a secret file. The example binds the port to loopback.

bash
docker inspect --format '{{.State.Health.Status}}' postvec

The 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-remote

Volume path ​

PostgreSQL majorMount
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.

VariableDefaultMeaning
POSTVEC_MODEpinned by the image: grpc in *-remote, embedded in *-localInference mode
POSTVEC_DATABASESPOSTGRES_DBComma-separated worker databases
POSTVEC_GRPC_ENDPOINTSunsetRemote gRPC
POSTVEC_HTTP_ENDPOINTSunsetRemote /config
POSTVEC_PATH/opt/postvecEmbedded engine root
POSTVEC_PROVIDERS_PATH/etc/postvec/providers.d in *-local, unset in *-remoteDirectory postvec provider reads when --path is absent
POSTVEC_EMBEDDED_MODELSbundled modelPreload allow-list
POSTVEC_SHARED_PRELOAD_LIBRARIESunsetExisting preloads; postvec is appended
POSTVEC_CREATE_EXTENSION10 skips first-run CREATE EXTENSION
POSTVEC_HEALTHCHECK_DATABASEPOSTGRES_DBDatabase postvec-healthcheck connects to
POSTVEC_HEALTHCHECK_BEAT_AGEunset; heartbeat interval + three poll ticks + 2 sWorker 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
MountContentsPermissions
/etc/postvec/providers.dOne *.toml connector file per providerDirectory 0700, files 0600, owned by the container's postgres uid (999)
Any path you referenceThe api_key_file a connector points at0600, 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.

sql
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:

bash
docker exec postvec postvec-healthcheck
bash
docker exec -u postgres postvec \
  postvec doctor \
  --database-url 'postgresql:///app?host=/var/run/postgresql' \
  --database app

Persistent 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:latest

Every 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.