.NETpgvectorPostgreSQLEmbeddings

Vector Search in .NET with pgvector and PostgreSQL

You do not need a new database for vector search. Use pgvector in PostgreSQL from .NET to store embeddings and run similarity queries — with the database you already run.

When teams add semantic search or RAG, the reflex is to bolt on a dedicated vector database. Often you don’t need to. If you already run PostgreSQL, the pgvector extension gives you vector storage and similarity search in the database you know — no new infrastructure, no separate service to operate. Here’s how to use it from .NET.

Why pgvector

Dedicated vector databases are excellent at massive scale. But for a lot of applications, pgvector on Postgres is the pragmatic choice:

  • One database — your relational data and your vectors live together; you can filter by metadata and similarity in a single SQL query.
  • Nothing new to operate — you already back up, monitor, and secure Postgres.
  • It scales further than people expect — comfortably into millions of vectors with the right index.

Step 1: Enable the extension and create a table

CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE documents (
    id        bigserial PRIMARY KEY,
    content   text NOT NULL,
    embedding vector(1536)      -- match your embedding model's dimensions
);

The vector(1536) column stores the embedding; set the size to your model’s output dimensions.

Step 2: Insert embeddings from C#

Generate an embedding and store it alongside the text. With Npgsql (which has pgvector support), you write the vector directly:

// Pseudocode-level: generate the vector, then insert it with the text.
var vector = (await embedder.GenerateAsync(content)).Vector.ToArray();

await using var cmd = new NpgsqlCommand(
    "INSERT INTO documents (content, embedding) VALUES ($1, $2)", conn);
cmd.Parameters.AddWithValue(content);
cmd.Parameters.AddWithValue(new Vector(vector));   // Npgsql pgvector type
await cmd.ExecuteNonQueryAsync();

Step 3: Search by similarity in SQL

pgvector adds distance operators. The <=> operator is cosine distance — order by it and take the nearest rows:

SELECT content
FROM documents
ORDER BY embedding <=> $1     -- $1 = your query embedding
LIMIT 5;

From C#, you embed the query, pass the vector as $1, and read back the top matches. The power move: combine it with a normal WHERE — “the 5 most similar documents for this tenant, in this category” — something a bolt-on vector store makes awkward but Postgres does in one query.

Step 4: Add an index for speed

Without an index, Postgres scans every row. For real datasets, add an approximate-nearest-neighbour index (HNSW is a good default):

CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);

This trades a tiny bit of recall for a large speed-up — the standard bargain for vector search at scale.

Note: Npgsql’s pgvector type names and index options evolve; verify against the pgvector and Npgsql docs. The approach — a vector column, <=> for similarity, an HNSW index — is stable.

Takeaway

pgvector gives .NET teams vector search without adopting a new database: enable the extension, add a vector column, insert embeddings via Npgsql, and query with the <=> distance operator plus an HNSW index. You keep your relational data and vectors together — filtering by metadata and similarity in one SQL query — on infrastructure you already run. For most apps, that’s the right amount of vector database.

Next: how pgvector compares to Qdrant, Azure AI Search and SQL Server 2025 if you are still choosing a store.


Have a correction or a topic you want covered? Email mani.bc72@gmail.com.