Skip to content

How it works ​

Vectors fill after commit. Automatic sync needs shared_preload_libraries = 'postvec' and a restart. Until an ANN index exists, search scans the vector column sequentially.

Runtime ​

postvec runtime shapeInside the PostgreSQL cluster, a trigger on the source table enqueues work into postvec.jobs; a per-database worker spawned by the launcher claims the job and writes the vector back to the same table. The worker calls an inference engine that is either the launcher on loopback or a remote postvec-server.POSTGRESQL CLUSTERTRIGGERCLAIMWRITE-BACKSPAWNSgRPCTABLESource tablebody → body_semanticQUEUEpostvec.jobscoalesced per rowWORKERPer-database workerone per postvec.databaseLAUNCHERLaunchershared_preload_librariesENGINEInference enginelauncher loopback, or a remote postvec-server

CREATE EXTENSION exposes the SQL surface immediately. Automatic sync needs shared_preload_libraries = 'postvec', a restart and a worker for that database. SELECT postvec.start_worker() starts that worker now, as a superuser, so the database is served before the restart. Inference runs in the launcher by default; postvec-server runs the same jobs in a separate process.

Write path ​

The write path, and the window where the vector is emptyFour steps left to right: the application commits, a trigger enqueues the row into postvec.jobs, the worker claims it and calls inference, and the worker writes the vector. A bracket spans from the commit to that write marking the window in which the stored vector is null or stale.VECTOR NULL OR STALE1CommitINSERT / UPDATE2Enqueuecoalesced per row3Claim + embedre-reads the text4Write-backbody_semantic

Between the application commit and the worker writing the vector, the column is NULL or stale. A commit wakes the worker, so the gap is normally just inference time. See eventual consistency.

search() embeds the query synchronously.

Durable and transient state ​

Durable (dumped)Cache (not dumped)
registry, jobs, jobs_dead, migrationspostvec.models, worker heartbeat

A restore needs matching files, cluster configuration, a model refresh and doctor. Backup has the checklist.

Operational constraints ​

  1. Vectors fill after commit. status() reports readiness.
  2. The worker needs preload to survive a restart. Every database named in postvec.database must exist. A missing name makes the worker fail and respawn on an escalating quarantine, 15 s to 5 min, until the database appears; a worker that lives past 30 s resets the ladder. Managed databases cannot preload: they run the worker in postvec-server instead.
  3. ANN indexes are opt-in. Missing ANN is a common reason search is slow. index_mode => 'auto' is available; in the extension the build is blocking, while the managed sync worker builds on its own connection with CREATE INDEX CONCURRENTLY.
  4. A new library and ALTER EXTENSION belong in one window. Until then the worker pauses.
  5. adopt()'s model is an assertion. The wrong name makes search() embed into an incompatible space.