Semantic Search, Built Into Your Postgres
Adding semantic search to an app usually means standing up a second database. You pick a vector store, write an embedding pipeline, keep it in sync with your real data, and now you have two systems to operate, two bills to pay, and a consistency problem you didn't have yesterday.
Rivestack takes the other path: semantic search is just your Postgres. The same dedicated database that holds your application data runs pgvector with an HNSW index on always-on NVMe — and we've built a Semantic Search workspace right into the dashboard so you can use it without wiring anything together first.
This post walks through what it does, how to try it in about thirty seconds, and the honest numbers behind it.
It's your database, not a second one#
There is no separate vector service to provision, no replication to configure, and nothing to keep in sync. Your embeddings live in a vector column next to the rows they describe, so a semantic query is a normal SQL query — you can join it to other tables, filter it with a WHERE clause, and wrap it in a transaction, all in one place.
Under the hood, a search is exactly what you'd write by hand:
SELECT id, content, category,
1 - (embedding <=> $query_vector) AS similarity
FROM documents
ORDER BY embedding <=> $query_vector
LIMIT 10;<=> is pgvector's cosine-distance operator, and the ORDER BY ... LIMIT is served by the HNSW index. The Semantic Search page just gives you a UI over this, and embeds your query text into $query_vector for you.
Try it in about 30 seconds#
Open Semantic Search in the dashboard and pick a database. If you don't have a vector table yet, click Generate sample dataset — it creates a fresh table of ~1,800 short documents across eight topics (space, cooking, programming, animals, music, finance, travel, fitness), generates real embeddings for each, and builds the HNSW index.
Then type a query in plain language — "how do rockets reach orbit", "keeping data consistent across servers" — and you'll get results ranked by meaning, not keywords. A document about distributed consensus ranks for "keeping data consistent across servers" even if it never uses those exact words. That's the whole point of semantic search, and you didn't write a line of code to see it.
Embeddings are generated for you#
The friction in most vector setups isn't the search — it's producing the embeddings and keeping them current. Rivestack handles that side too.
Anywhere you'd insert text that should be searchable, you give us the text and we produce the vector with OpenAI's text-embedding-3-small (1536 dimensions). In the built-in Table editor, inserting a row into a table that has a vector column shows a From text mode: type a sentence, and it's embedded into the column on insert — you never hand-build an array of 1,536 floats.
If you'd rather do it in your own code, the same model is one call away, and storing the result is ordinary SQL:
-- documents.embedding is vector(1536)
INSERT INTO documents (content, embedding)
VALUES ('A cozy cabin in the woods', '[0.0123, -0.0456, ...]');pgvector stores a vector as float4, so you don't need to send full double precision — float32 is exactly what gets stored, which keeps your inserts small and fast.
Numbers measured by Postgres#
Performance claims are easy to inflate, so we made the Semantic Search page show numbers you can trust. The query time it reports comes from EXPLAIN ANALYZE — Postgres's own measurement of how long it spent executing the query, which excludes the network round-trip, connection setup, and the embedding API call. On an indexed table that's typically sub-millisecond. The page also shows whether the HNSW index was actually used (straight from the plan) and a warm p50/p95 over several runs.
For scale, our published benchmarks come from pgvector-bench, our open-source CLI you can run against your own database. On clustered 1,536-dimension data with an HNSW index (m = 16, ef_construction = 64) at recall@10 of 0.93, a $15 node serves about 1,000 QPS at a 3.7 ms p50 (4 concurrent clients) and scales to about 1,570 QPS at a 10 ms p50 (16 clients); a Scale node reaches roughly 2,500 QPS. Throughput and latency climb together — you don't get peak QPS at the lowest p50 — and every number is measured over the same client path your app would use, and reproducible. The full per-tier methodology is in our benchmark writeup.
Why Postgres is the right home for this#
A dedicated vector database makes sense at a certain scale and shape of workload. For the vast majority of applications, it's overkill — and it costs you the things a relational database is good at:
- Joins and filters. Combine a semantic match with
WHERE tenant_id = $1 AND publishedin a single query, against indexes you already have. - One source of truth. Embeddings sit with their rows. No pipeline drift, no "the vector store is stale" incidents.
- Transactions. Insert a document and its embedding atomically.
- One bill, flat pricing. Rivestack starts at $15/month for a dedicated node, with no per-query or per-vector metering.
- No cold starts. Always-on NVMe — your first query of the day is as fast as your thousandth.
And if you genuinely have a workload that needs a specialized vector engine, we'll tell you that honestly rather than sell you a node that won't keep up.
Get started#
Semantic Search is available on every Rivestack database, including the free tier (a shared instance); dedicated NVMe nodes start at $15/month.
- Open Semantic Search and generate the sample dataset to try it now.
- Read the docs for the full workflow, or learn the fundamentals in What is pgvector?
- Benchmark your own setup with pgvector-bench.
Semantic search shouldn't require a second database. On Rivestack, it's already in the one you have.