turbopuffer searches. semantic-router decides. Semantik delivers.
Three tools with overlapping vocabulary and no overlapping job. turbopuffer and every other vector database answer a question when you ask. semantic-router picks which branch handles a request. Semantik answers a question you asked once, every time the answer changes.
With turbopuffer you hold the query in your code and decide when to run it. Something in your system has to notice that it is time to ask: a request, a cron, a queue drain. The query runs, you get ranked results back, and the question is closed until you ask again.
With Semantik you hand the query to the server and hold a connection instead. Every message published after that is matched against your query, and each match arrives on the connection as it happens. Nothing in your code decides when to ask, because nothing asks.
That is the whole distinction, and it decides which one you want. If the value is in searching a corpus, turbopuffer's shape is right. If the value is in knowing early, a polling loop is the wrong instrument no matter how fast the search underneath it is.
Everything below applies to vector databases generally, not just to turbopuffer. Pinecone, Qdrant, Weaviate, Chroma and pgvector differ from each other on cost, hosting and index type, and they are identical to each other on the axis this page is about: you ask, they answer.
| turbopuffer | Semantik | |
|---|---|---|
| Interaction model | Pull. You issue a query, you get results. | Push. You register a query once, matches arrive. |
| Built around | Vector and full-text search over object storage | Matching every publish against every live query |
| Query shape | Vector similarity with filters, plus full-text | SemQL predicates: DISTANCE, DIRECTION, CONTRAST, composed with AND, OR, NOT |
| How soon you learn about new content | Your polling interval | On the open stream, when the match happens |
| Looking backward | The core capability, at large corpus size | Search over the messages in your namespace |
| Where the query lives | In your code | On the server |
| Delivery guarantees | Not applicable, it is a query | At-least-once, dedupe on message_id |
| Ordering | Not applicable | None |
| You operate | Nothing | Nothing |
Reach for turbopuffer when
- Retrieval over a large corpus is the job, and the corpus keeps growing. That is what turbopuffer is designed for, and its object-storage design is what keeps the cost curve flat as it grows.
- You want vector and full-text search answered by one query.
- Something in your system already decides when to ask. If a request or a job naturally triggers the lookup, push buys you nothing.
- The corpus is documents rather than events. Semantik's search covers the messages in your namespace and is not meant to be your document store.
Semantik is the wrong tool when
- You need per-partition ordering or exactly-once delivery. Semantik gives neither, and does not pretend to.
- You need the lowest cost per stored vector at corpus scale. That is turbopuffer's design point, not ours.
- You want one system to be both the document store and the delivery path. Semantik is the delivery path.
Reach for both when
Keep the searchable corpus where search is best, and take the live trigger from Semantik. A subscription matches, your consumer gets a message_id, and your enrichment step queries whichever store holds the rest. The two tools answer different questions, and there is no reason to make one of them do the other's job badly.
You are probably also weighing
Vector databases
Pinecone, Qdrant, Weaviate, Chroma, pgvector and turbopuffer itself. They store embeddings and answer similarity queries on demand.
They are the same shape as turbopuffer for this comparison: the query lives in your code and runs when something decides to run it. Semantik holds the query and pushes matches as they happen. Plenty of systems keep a vector database for the corpus and take the live trigger from Semantik.
semantic-router
Aurelio Labs' decision layer. It classifies an incoming utterance and picks which route, tool or prompt should handle it, in-process and on the hot path of a single request.
It chooses a branch inside one process. Semantik moves a message between processes. The names collide and the jobs do not: you could reasonably run semantic-router to decide what an agent does next, and Semantik to tell other agents it did it.
turbopuffer is a well-built product with a clear design point. This page is written from its public documentation as of August 23, 2026, not from a benchmark we ran, and where we do not have a fair number we have left the cell empty rather than putting one there. Check it yourself.