pg_pinecone vs. pgvector: Choosing a Postgres Vector Engine
Pinecone published pg_pinecone on October 27: an Apache-2.0 Postgres extension that puts the search engine Pinecone runs in its own cloud inside the database you already operate. The interesting part is not that another vendor shipped an extension. It is that pg_pinecone reuses your existing vector columns and your existing ORDER BY embedding <=> $1 queries, so changing engines is a function call rather than a migration project.
That changes the decision from “pgvector or a second system” to “which engine should answer this table’s queries.”
Three engines behind one index
pg_pinecone requires PostgreSQL 17 or 18, superuser access, and pgvector already installed, because it builds on pgvector’s vector type and distance operators. Each table gets one pg_pinecone index with an engine setting:
pgvector— your existing HNSW or IVFFlat index, left exactly as it is.native(the default) — Pinecone’s engine running inside Postgres, with no account, no API key and no network calls.remote— search runs on a Pinecone serverless index kept in sync with the table; Postgres keeps every row.
CREATE EXTENSION vector;
CREATE EXTENSION pg_pinecone;
CREATE TABLE docs (
id bigint PRIMARY KEY,
tenant_id bigint,
body text,
embedding vector(768)
);
-- native engine, with tenant_id available as a filter during the search
SELECT pinecone.create_index('docs', 'embedding', filter_column => 'tenant_id');
-- the query your application already sends
SELECT id, body FROM docs
WHERE tenant_id = $1
ORDER BY embedding <=> $2
LIMIT 10;
Switching later is SELECT pinecone.set_engine('docs', 'remote');, and every switch can be reversed. The remote engine and the BM25 full-text index need shared_preload_libraries = 'pg_pinecone' and a restart.
Why the index is small: IVF and RaBitQ, not a graph
HNSW stores a full copy of every vector plus links to its nearest neighbours; a search walks that graph comparing full vectors at each hop, which is why the index wants to sit in RAM. The native engine clusters vectors with an inverted file and stores a RaBitQ code per vector: roughly one bit per dimension plus a few correction values. A query probes the nearest clusters, estimates distances from the codes, then reranks a shortlist against full vectors from your table.
Pinecone’s published benchmark harness, 1M vectors at 768 dimensions on an r6id.4xlarge, reports:
- Index size: 136 MB native, against 2.0 GB for HNSW on
halfvecand 4.1 GB on full-size vectors. - Build time: 45 s native, against 62 s and 79 s.
- p50 latency at k=10: 1.27 ms at 0.95 recall (1.71 ms for HNSW on
halfvec), and 2.28 ms at 0.99 recall (4.65 ms).
Those are vendor numbers on a public dataset: a reason to run the test, not a result you inherit. What transfers between datasets is the shape of the trade: a much smaller index, cheaper builds, and recall that depends on quantization quality instead of graph connectivity.
The real argument is filtered search
Production vector queries are rarely “nearest neighbours in the corpus.” They are “nearest neighbours for this tenant, this document set.” With an approximate index, pgvector applies the WHERE clause after the index scan. Filter down to one tenant in a hundred and a LIMIT 10 can come back with three rows. pgvector 0.8.0 added iterative index scans that keep scanning until the limit is met, which is a real fix — paid for by scanning more of the index.
The native engine filters during the search. It stores the filter column’s value next to each vector’s code and picks a strategy by selectivity:
- Narrow filter (3% of rows or fewer by default): pre-filtering. Every matching row is scored with its full vector, so the result is exact.
- Wider filter: single-stage filtering. The engine probes more clusters than an unfiltered search and checks the filter inside each cluster before scoring.
-- pgvector 0.8+: keep scanning until the LIMIT is satisfied
SET hnsw.iterative_scan = relaxed_order;
-- pg_pinecone native: the filter is applied inside the search
SELECT id, body FROM docs
WHERE tenant_id = 42
ORDER BY embedding <=> $1
LIMIT 10;
In the hard case where the true nearest matches mostly fall outside the filter, Pinecone reports 0.981 recall at 8.3 ms for a 1% filter, against 0.924 at 56 ms for HNSW with iterative scans. At a 10% filter it reports 1.000 recall at 12.3 ms, against 0.922 at 5.1 ms — HNSW was faster, the native engine was more complete. If your search returns three rows when the interface promised ten, that is the number that costs you a support ticket, not the one in the latency chart.
What to check before you deploy it
- Version currency. This is 0.11.0, the first public release, and it was called
pinegresuntil 0.10.0 — a rename with no upgrade path. Read the changelog before pinning it, and budget for extension upgrades. - Managed Postgres. Installing needs superuser, and
remoteplus full-text search need a preloaded library and a restart. On RDS, Aurora, Cloud SQL and similar, that usually means waiting on the provider’s allowlist — confirm availability before designing around it. - Restore. The index is derivable from the table, so it belongs in your rebuild path, not your backup. With
remote, the Pinecone index is a second system with its own restore procedure; Pinecone ships a runbook for restoring both together — rehearse it once. - Staleness. Centroids are fixed at build time: a bulk load that doubles the table, or data unlike what the index was built on, needs
REINDEXor automatic maintenance. - The lock-in question.
nativeis Apache 2.0 and asks nothing of Pinecone.remote,embed(),rerank()and the BM25 index are Pinecone services — a reasonable escalation, a poor default.
-- after a bulk load that reshapes the data, rebuild rather than wait
REINDEX TABLE docs;
-- confirm the engine and index state on a table you inherited
SELECT * FROM pinecone.status();
The decision, in one paragraph
Stay on pgvector if your searches are unfiltered, the index fits in memory and recall is acceptable; it is boring, it is everywhere, and it is already installed. Move a specific table to native when you have a narrow filter you cannot index around, an HNSW index competing with your buffer cache, or builds that take too long to re-run. Reach for remote only when one server has actually run out of room, and only after measuring it, because “we might outgrow this” has a way of paying for a second system for two years.
For the index-shape side of the same decision — HNSW, DiskANN, or no graph at all — see Postgres vector indexes in 2026. If you are blending vector and keyword search, the pgvector, tsvector and RRF recipe still applies unchanged on the native engine.
Houston teams running tenant-scoped search on Postgres — trading documents, well logs, compliance filings — usually meet this as a recall problem before a latency problem, and a recall problem is the one you cannot page anyone for. If you are deciding between engines this quarter, get a second opinion on your Postgres vector search design before you migrate.
