All posts

MongoDB or Postgres: where should your vectors live?

You probably don't need a separate vector database on day one. How I decide between Atlas Vector Search, pgvector and a dedicated store.

2 min read

  • Databases
  • AI
  • MongoDB
  • Postgres

Every AI feature eventually asks the same question: where do the embeddings go? The tempting answer is a new, specialised vector database. Sometimes that is right. Often, the database you already run is the better first choice.

Start with the data you already have

Embeddings are rarely useful on their own. You filter them by tenant, by permissions, by document type, by date. If your documents already live in MongoDB or Postgres, keeping vectors next to them means those filters are ordinary queries, and there is no second system to keep in sync.

If the application is already on MongoDB Atlas, vector search is an index on a field you already have. Queries run through the aggregation pipeline, so filtering and projection feel familiar:

js
db.chunks.aggregate([
  {
    $vectorSearch: {
      index: "chunks_vector",
      path: "embedding",
      queryVector: embedding,
      numCandidates: 200,
      limit: 10,
      filter: { tenantId: "acme" },
    },
  },
  { $project: { text: 1, docId: 1, score: { $meta: "vectorSearchScore" } } },
]);

It suits document-shaped data, flexible schemas and teams who already think in pipelines.

Postgres with pgvector

If the app is relational, pgvector adds a vector column type and approximate indexes such as HNSW:

sql
create extension if not exists vector;

create table chunks (
  id bigserial primary key,
  tenant_id text not null,
  text text not null,
  embedding vector(1536)
);

create index on chunks using hnsw (embedding vector_cosine_ops);

The big win is joins and transactions. Permissions, soft deletes and full-text search all live in the same query, and a chunk is written in the same transaction as the document it came from.

When a dedicated vector store earns its place

A separate service starts to make sense when:

  • vector volume is far larger than the rest of your data,
  • you need features your primary database does not offer yet,
  • search traffic needs to scale independently from writes.

Even then, keep the source of truth in your main database and treat the vector store as a derived index you can rebuild.

How I decide

  1. Already on Atlas? Use Atlas Vector Search.
  2. Relational app on Postgres or Supabase? Use pgvector.
  3. Hitting real limits at scale? Add a dedicated store as a rebuildable index.

Whatever you choose, store the embedding model name and dimension with every vector. Models change, and a clean re-embed is much easier when you know exactly what produced the vectors you have.

Found this useful? Share it with someone building the same thing.

Building something like this?

Have a project, a role, or just an idea worth exploring? Drop me a message. I usually reply within a day.