Build1 distinct publisher3 min readPublished
The dedicated store won every unfiltered benchmark this team ran, which happened to be the one query their product never issued. What they were paying for was a copy of derived data that could disagree with its source in silence.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
The only stopwatch number in the post goes against the change it argues for: bare k nearest vectors, no filter, warm cache, and the dedicated store won every time [2]. There is no filtered p95 for the pgvector version, no recall figure, no bill [16]. The author says his own headline oversells the speed claim [17]. So the case for deletion rests on something other than latency, and it is worth being exact about what.
The two filtering strategies are the mechanism, and they are not a vendor defect. Pre-filter, and the store walks metadata first and brute-forces similarity over the survivors, which discards the approximate index you bought it for [4]. Post-filter, and it keeps the index but pays in recall: ask for 10, match on distance, find that 7 rows belong to another tenant, return 3 [5]. Over-fetching top 100 or top 500 does not bound the loss, because the shortfall depends on how badly the filter correlates with the vector space, and it is worst exactly when the filter is most selective [5]. Any approximate index meets that same fork when a WHERE clause arrives. Which fork Postgres took for their filtered query is not in the post, and it is the first thing I would measure before copying the architecture.
They had already conceded the read path in code. Post-filter, then fetch back to Postgres for the metadata the vector store did not hold, then filter again to be sure, on every query [6]. Two systems answering one question, one of them because the other could not.
The write path is where the deletion actually pays. The embedding is a pure function of the document body, derived the way a thumbnail is derived from an image, and it was living in a different database from its source [7]. Every write was two writes [8]. When the embed-and-upsert fails after the row commits, nothing throws and nothing alerts; the document quietly cannot be found, or is found by its old content [9]. Run it the other way and a delete in Postgres that fails in the vector store returns a chunk of a document that no longer exists, to a user who may no longer be cleared to see it [10]. The author's name for this is the dual-write problem, the seam the transactional-outbox literature has been on about for a decade [11].
The alternative to deleting the store is building the machine: tail the WAL, transform, re-embed, upsert, dead-letter the failures, and run a reconciliation scan because you know the pipeline drifts [12]. Six stages [14], and the sixth exists because you have already accepted that the first five do not hold. That was most of the 1,100 lines [12].
Adoption cost lands in your primary, because the replacement is a column on the table the application already reads [1]. Price it: 3.2M vectors [1] at 1536 dimensions [13] is 4.9 billion floats, and at four bytes each that is roughly 19.7 GB [15] before HNSW overhead, in your backups and on your replicas.
For that trade to transfer, three things have to be true of your workload: every retrieval carries a tenant or ACL predicate [3], the embedding is a pure function of a row you already own [7], and 20 GB plus an index in the primary is not a problem. If you genuinely search a whole corpus unfiltered, the benchmark the vendor wins is your query [2], and none of this applies.
Ranked by verification strength, evidence, and original report placement.
The team's change removed a managed vector store holding 3.2M vectors, with its own SLA and its own bill, and a 1,100-line sync pipeline that kept it in step with Postgres; it added one column, embedding vector(1536), and one hnsw index to the existing documents table.
Every retrieval they ran in production was: find the chunks most similar to this question, among documents this user is allowed to see, that are published, in their workspace, not archived.
Pre-filtering in a dedicated vector store walks the metadata first, then does brute-force similarity over what survives, throwing away the ANN index.
Post-filtering takes the top k by vector distance then drops rows failing the filter: ask for 10, discover 7 belong to a different tenant, return 3. Over-fetching top 100 or top 500 is a hope, because recall becomes a function of how badly the filter correlates with the vector space, which is unknowable and worst exactly when the filter is selective.
They shipped the post-filter version, then bolted on a fetch-back: take the surviving IDs, go to Postgres for the metadata the vector store did not hold, and filter again to be sure, a second network hop on every query.
The author argues the embedding is not data but a pure function of data, derived the way a thumbnail is derived from an image, and they were storing the derived thing in a different database from the thing it was derived from.
Distinct publishers with included, body-backed reporting in this cluster.
1 article · September 6, 2026
Follow any of these and your For You feed starts watching them — no settings page required.
build
The query a vector index cannot answer, whatever you embed it with1 distinct publisher
build
A RAG stack lived seven hours before a hosted embedding endpoint returned 4041 distinct publisher
build
A reply bot's confidence score was always 0.85, because it was typed in, not computed1 distinct publisher
build
PostgreSQL 16 and pgvector cover the three read patterns a swarm gateway actually needs1 distinct publisher
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Single first-person account
Everything specific traces to one engineer describing his own system on dev.to: the 3.2M vectors, the 1,100 lines, the store that won the benchmark. That store is never named, the benchmark carries no numbers, and the Postgres side is shown as SQL and planner behaviour rather than as results. What a reader can check independently is the technical spine, pgvector's vector(1536) type and HNSW index, the two filtering strategies a separate store has to choose between, and the dual-write seam the outbox pattern exists to close, and that spine holds on its own terms.
One team, one migration
A single swap, described after the fact by the people who made it. The broader anchor is capability rather than uptake: HNSW has been in pgvector since 0.5.0 in August 2023, so the index this team relied on has been generally available for two years. Nothing here indicates how many other teams have consolidated the same way, or how the column behaves past 3.2M rows.
Headline outruns the body
The title promises Postgres was faster and the second paragraph withdraws it: on the unfiltered benchmark the dedicated store won every time, in the author's own account. The claim that survives is narrower and better supported, that the benchmark's query was never the query the product issued. The post also concedes that an HNSW index returns a fixed candidate set, so a selective filter reproduces the same post-filter shortfall inside Postgres, which trims the tidy ending the headline sets up.
Tooling advocacy, no disclosed stake
A developer-community post arguing against a product category with no vendor named and no relationship declared in either direction. The visible stake is reputational: the piece takes a swing at the 'just use a real vector database' crowd while also correcting its own headline. Nothing in it points to a sponsor, a product or a pgvector affiliation, and nothing rules one out either.
Auditable argument, unauditable benchmark
The mechanism claims are the sort a reader can check against their own stack: two writes where one can fail, a stale vector answering for a deleted row, the pre-filter and post-filter dilemma. They are internally consistent and independent of this team's implementation. The comparative performance story rests on an unaudited benchmark with the figures withheld, and no second party has seen any of it. High confidence in the diagnosis, little in anything shaped like a measurement.