Vector Database
How CodePilot uses PostgreSQL with pgvector for efficient similarity search over code embeddings.
CodePilot stores and queries vector embeddings using PostgreSQL with the pgvector extension. This avoids the need for a separate vector database like Pinecone or Weaviate — everything lives in a single PostgreSQL instance.
Why pgvector?
| Alternative | Trade-off |
|---|---|
| Pinecone | Managed service, requires API key, adds network latency |
| Weaviate | Separate service to deploy and maintain |
| ChromaDB | In-memory, limited persistence |
| pgvector | Runs inside existing PostgreSQL — zero additional infrastructure |
Since CodePilot already uses PostgreSQL for application data (users, repositories, sessions), adding pgvector keeps the architecture simple. All data lives in one database with one backup strategy.
Setup
pgvector is included in the Docker image pgvector/pgvector:pg18:
services:
postgres:
image: pgvector/pgvector:pg18
container_name: codepilot_postgres
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- "${POSTGRES_PORT:-5432}:5432"
volumes:
- postgres_data:/var/lib/postgresqlThe extension is enabled via a Prisma migration:
CREATE EXTENSION IF NOT EXISTS vector;Schema
Embeddings are stored in the CodeEmbedding table:
model CodeEmbedding {
id String @id @default(cuid())
chunkId String
chunk CodeChunk @relation(fields: [chunkId], references: [id])
embedding Unsupported("vector(768)")
repositoryId String
repository Repository @relation(fields: [repositoryId], references: [id])
createdAt DateTime @default(now())
}Prisma and pgvector
Prisma uses Unsupported("vector(768)") for the embedding column since pgvector types are not natively supported by Prisma's type system. Raw SQL queries are used for vector operations.
Indexing
CodePilot uses HNSW (Hierarchical Navigable Small World) indexing for fast approximate nearest-neighbor search:
CREATE INDEX idx_code_embedding_hnsw
ON "CodeEmbedding"
USING hnsw ("embedding" vector_cosine_ops);HNSW vs. IVFFlat
| Index Type | Build Time | Query Speed | Recall | Memory |
|---|---|---|---|---|
| HNSW | Slower | Faster | Higher | Higher |
| IVFFlat | Faster | Slower | Lower | Lower |
HNSW is preferred because it provides better recall and query speed, which directly impacts the quality of RAG responses.
Similarity Search
Queries are performed using cosine distance (<=>) operator:
SELECT
ce."id",
cc."content",
cc."filePath",
cc."startLine",
cc."endLine",
ce."embedding" <=> $1::vector AS distance
FROM "CodeEmbedding" ce
JOIN "CodeChunk" cc ON cc."id" = ce."chunkId"
WHERE ce."repositoryId" = $2
ORDER BY ce."embedding" <=> $1::vector
LIMIT 10;The $1 parameter is the query embedding vector, and $2 is the repository ID. Results are ordered by cosine distance (lower = more similar).
Performance
For a repository with ~5,000 code chunks:
| Operation | Approximate Latency |
|---|---|
| Insert 1 embedding | ~1ms |
| Bulk insert 100 embeddings | ~50ms |
| Similarity search (top 10) | ~5–15ms |
| Full ingestion (embed + store) | Depends on repo size |
pgvector with HNSW handles repositories with tens of thousands of chunks efficiently. For larger codebases, the index parameters (m and ef_construction) can be tuned.