pgvector support for .NET (C#, F#, and Visual Basic)
Supports Npgsql, Dapper, Entity Framework Core, and Npgsql.FSharp
Getting Started
Follow the instructions for your database library:
- C# - Npgsql, Dapper, Entity Framework Core
- F# - Npgsql.FSharp
- Visual Basic - Npgsql
Or check out some examples:
- Embeddings with OpenAI
- Binary embeddings with Cohere
- Hybrid search with Ollama (Reciprocal Rank Fusion)
- Sparse search with Text Embeddings Inference
- Recommendations with Disco
- Topic modeling with ML.NET
- Horizontal scaling with Citus
- Bulk loading with
COPY
Npgsql (C#)
Run
dotnet add package Pgvector
Create a connection
var dataSourceBuilder = new NpgsqlDataSourceBuilder(connString); dataSourceBuilder.UseVector(); await using var dataSource = dataSourceBuilder.Build(); var conn = dataSource.OpenConnection();
Enable the extension
await using (var cmd = new NpgsqlCommand("CREATE EXTENSION IF NOT EXISTS vector", conn)) { await cmd.ExecuteNonQueryAsync(); } conn.ReloadTypes();
Create a table
await using (var cmd = new NpgsqlCommand("CREATE TABLE items (id serial PRIMARY KEY, embedding vector(3))", conn)) { await cmd.ExecuteNonQueryAsync(); }
Insert a vector
await using (var cmd = new NpgsqlCommand("INSERT INTO items (embedding) VALUES ($1)", conn)) { var embedding = new Vector(new float[] { 1, 1, 1 }); cmd.Parameters.AddWithValue(embedding); await cmd.ExecuteNonQueryAsync(); }
Get the nearest neighbors
await using (var cmd = new NpgsqlCommand("SELECT * FROM items ORDER BY embedding <-> $1 LIMIT 5", conn)) { var embedding = new Vector(new float[] { 1, 1, 1 }); cmd.Parameters.AddWithValue(embedding); await using (var reader = await cmd.ExecuteReaderAsync()) { while (await reader.ReadAsync()) { Console.WriteLine(reader.GetValue(0)); } } }
Add an approximate index
await using (var cmd = new NpgsqlCommand("CREATE INDEX ON items USING hnsw (embedding vector_l2_ops)", conn)) { await cmd.ExecuteNonQueryAsync(); }
Use vector_ip_ops for inner product and vector_cosine_ops for cosine distance
See a full example
Dapper
Run
dotnet add package Pgvector.Dapper
Import the library
Create a connection
SqlMapper.AddTypeHandler(new VectorTypeHandler()); var dataSourceBuilder = new NpgsqlDataSourceBuilder(connString); dataSourceBuilder.UseVector(); await using var dataSource = dataSourceBuilder.Build(); var conn = dataSource.OpenConnection();
Enable the extension
conn.Execute("CREATE EXTENSION IF NOT EXISTS vector"); conn.ReloadTypes();
Define a class
public class Item { public int Id { get; set; } public Vector? Embedding { get; set; } }
Also supports HalfVector and SparseVector
Create a table
conn.Execute("CREATE TABLE items (id serial PRIMARY KEY, embedding vector(3))");
Insert a vector
var embedding = new Vector(new float[] { 1, 1, 1 }); conn.Execute(@"INSERT INTO items (embedding) VALUES (@embedding)", new { embedding });
Get the nearest neighbors
var embedding = new Vector(new float[] { 1, 1, 1 }); var items = conn.Query<Item>("SELECT * FROM items ORDER BY embedding <-> @embedding LIMIT 5", new { embedding }); foreach (Item item in items) { Console.WriteLine(item.Embedding); }
Add an approximate index
conn.Execute("CREATE INDEX ON items USING hnsw (embedding vector_l2_ops)"); // or conn.Execute("CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 100)");
Use vector_ip_ops for inner product and vector_cosine_ops for cosine distance
See a full example
Entity Framework Core
Run
dotnet add package Pgvector.EntityFrameworkCore
The latest version works with Entity Framework Core 9 and 10. For Entity Framework Core 8, use version 0.2.2 and this readme.
Import the library
using Pgvector.EntityFrameworkCore;
Enable the extension
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.HasPostgresExtension("vector"); }
Configure the connection
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseNpgsql("connString", o => o.UseVector()); }
Define a model
public class Item { public int Id { get; set; } [Column(TypeName = "vector(3)")] public Vector? Embedding { get; set; } }
Also supports HalfVector and SparseVector
Insert a vector
ctx.Items.Add(new Item { Embedding = new Vector(new float[] { 1, 1, 1 }) }); ctx.SaveChanges();
Get the nearest neighbors
var embedding = new Vector(new float[] { 1, 1, 1 }); var items = await ctx.Items .OrderBy(x => x.Embedding!.L2Distance(embedding)) .Take(5) .ToListAsync(); foreach (Item item in items) { if (item.Embedding != null) { Console.WriteLine(item.Embedding); } }
Also supports MaxInnerProduct, CosineDistance, L1Distance, HammingDistance, and JaccardDistance
Get the distance
var items = await ctx.Items .Select(x => new { Entity = x, Distance = x.Embedding!.L2Distance(embedding) }) .ToListAsync();
Get items within a certain distance
var items = await ctx.Items .Where(x => x.Embedding!.L2Distance(embedding) < 5) .ToListAsync();
Add an approximate index
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Item>() .HasIndex(i => i.Embedding) .HasMethod("hnsw") .HasOperators("vector_l2_ops") .HasStorageParameter("m", 16) .HasStorageParameter("ef_construction", 64); // or modelBuilder.Entity<Item>() .HasIndex(i => i.Embedding) .HasMethod("ivfflat") .HasOperators("vector_l2_ops") .HasStorageParameter("lists", 100); }
Use vector_ip_ops for inner product and vector_cosine_ops for cosine distance
See a full example
Npgsql.FSharp
Run
dotnet add package Pgvector
Import the library
Create a connection
let dataSourceBuilder = new NpgsqlDataSourceBuilder(connString) dataSourceBuilder.UseVector() use dataSource = dataSourceBuilder.Build()
Enable the extension
dataSource |> Sql.fromDataSource |> Sql.query "CREATE EXTENSION IF NOT EXISTS vector" |> Sql.executeNonQuery
Create a table
dataSource |> Sql.fromDataSource |> Sql.query "CREATE TABLE items (id serial PRIMARY KEY, embedding vector(3))" |> Sql.executeNonQuery
Insert a vector
let embedding = new Vector([| 1f; 1f; 1f |]) let parameter = new NpgsqlParameter("", embedding) dataSource |> Sql.fromDataSource |> Sql.query "INSERT INTO items (embedding) VALUES (@embedding)" |> Sql.parameters [ "embedding", Sql.parameter parameter ] |> Sql.executeNonQuery
Get the nearest neighbors
type Item = { Id: int Embedding: Vector } dataSource |> Sql.fromDataSource |> Sql.query "SELECT * FROM items ORDER BY embedding <-> @embedding LIMIT 5" |> Sql.parameters [ "embedding", Sql.parameter parameter ] |> Sql.execute (fun read -> { Id = read.int "id" Embedding = read.fieldValue<Vector> "embedding" }) |> printfn "%A"
Add an approximate index
dataSource |> Sql.fromDataSource |> Sql.query "CREATE INDEX ON items USING hnsw (embedding vector_l2_ops)" |> Sql.executeNonQuery
Use vector_ip_ops for inner product and vector_cosine_ops for cosine distance
See a full example
Npgsql (Visual Basic)
Run
dotnet add package Pgvector
Create a connection
Dim dataSourceBuilder As New NpgsqlDataSourceBuilder(connString) dataSourceBuilder.UseVector() Dim dataSource = dataSourceBuilder.Build() Dim conn = dataSource.OpenConnection()
Enable the extension
Using cmd As New NpgsqlCommand("CREATE EXTENSION IF NOT EXISTS vector", conn) cmd.ExecuteNonQuery() End Using conn.ReloadTypes()
Create a table
Using cmd As New NpgsqlCommand("CREATE TABLE items (id serial PRIMARY KEY, embedding vector(3))", conn) cmd.ExecuteNonQuery() End Using
Insert a vector
Using cmd As New NpgsqlCommand("INSERT INTO items (embedding) VALUES ($1)", conn) Dim embedding As New Vector(New Single() {1, 1, 1}) cmd.Parameters.AddWithValue(embedding) cmd.ExecuteNonQuery() End Using
Get the nearest neighbors
Using cmd As New NpgsqlCommand("SELECT * FROM items ORDER BY embedding <-> $1 LIMIT 5", conn) Dim embedding As New Vector(New Single() {1, 1, 1}) cmd.Parameters.AddWithValue(embedding) Using reader As NpgsqlDataReader = cmd.ExecuteReader() While reader.Read() Console.WriteLine(reader.GetValue(0)) End While End Using End Using
Add an approximate index
Using cmd As New NpgsqlCommand("CREATE INDEX ON items USING hnsw (embedding vector_l2_ops)", conn) cmd.ExecuteNonQuery() End Using
Use vector_ip_ops for inner product and vector_cosine_ops for cosine distance
See a full example
Reference
Vectors
Create a vector from an array
var vec = new Vector(new float[] { 1, 2, 3 });
Get an array
Half Vectors
Create a half vector from an array
var vec = new HalfVector(new Half[] { (Half)1, (Half)2, (Half)3 });
Get an array
Sparse Vectors
Create a sparse vector from an array
var vec = new SparseVector(new float[] { 1, 0, 2, 0, 3, 0 });
Or a dictionary of non-zero elements
var dictionary = new Dictionary<int, float>(); dictionary.Add(0, 1); dictionary.Add(2, 2); dictionary.Add(4, 3); var vec = new SparseVector(dictionary, 6);
Note: Indices start at 0
Get the number of dimensions
var dim = vec.Dimensions;
Get the indices of non-zero elements
var indices = vec.Indices;
Get the values of non-zero elements
Get an array
History
Contributing
Everyone is encouraged to help improve this project. Here are a few ways you can help:
- Report bugs
- Fix bugs and submit pull requests
- Write, clarify, or fix documentation
- Suggest or add new features
To get started with development:
git clone https://github.com/pgvector/pgvector-dotnet.git cd pgvector-dotnet createdb pgvector_dotnet_test dotnet test
To run an example:
cd examples/Loading
createdb pgvector_example
dotnet run