Series · 8 parts
pgvector for TypeScript
Eight posts that take one TypeScript project, a multimodal docs assistant searching text and screenshots, from a first similarity query to vector search you can tune, measure, and run in production. No second database.
You've done the hello-world. You have pgvector installed, you ran a similarity
query with <=>, and it sort of works. Now you're in the messy middle: results
that aren't quite right, queries slowing down as the table grows, and no clear
path to something you'd trust in front of users.
This series is the rest. It follows one continuous project, a docs assistant that searches Postgres documentation and screenshots in the same column, and works through the problems in the order they show up: get search working, make it relevant, make it fast, prove it's good with a number, then keep it good while the model upgrades and the corpus grows.
Every example is TypeScript. Everything runs on a Postgres you self-host. There is no second database anywhere in here. Most parts carry interactive demos: drag a query point around an embedding space, watch an index build, compare recall against latency.
This started life as a paid course. It's free now, and it lives here.
3 of 8 parts published
- 01Vector search in Postgres: the mental model behind pgvector
A first similarity query that returns results is not a finished search feature. This post explains what an embedding is, why one Postgres column can hold text and images, and where an untuned index starts returning wrong results.
- 02pgvector setup: your first multimodal query in TypeScript
One Postgres table can hold text and screenshot embeddings in the same vector column. This post sets up the schema, the Voyage embedding call, and the first query that returns both.
- 03Vector search relevance: chunking, metadata, and the 0.81 problem
Most bad vector search results come from one of three failure modes: chunking, modality mismatch, or a confused model. Each one has a specific diagnostic and a specific fix.