Agent Wranglers

Recommended Open source

Use pgvector in PostgreSQL before a separate vector database

Store embeddings in a pgvector column next to the rows they describe. Add a separate vector database only after a load test shows a limit PostgreSQL cannot meet.

Cost

Open source. PostgreSQL licence, free to run on your own servers. Managed PostgreSQL hosting is paid.

How to do it

pgvector is a PostgreSQL extension under the PostgreSQL licence. Its first release, 0.1.0, came out on 20 April 2021, and 0.8.7 came out on 1 October 2026. It has no 1.0 yet, but it has five years of production use. Its Python package had about 9 million weekly PyPI downloads in October 2026. One database means one backup, one set of permissions and plain joins between vectors and your data. It has HNSW and IVFFlat indexes with cosine, L2 and inner product distance. Keyword search lives in the same database, so Search by meaning and by words stays one query. Choose something else when a load test shows vector queries slowing your main database, or you must spread vectors over several machines. Then pick a vector database with an OSI licence and a tested export.

Examples

Using these examples: they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

SQL example

CREATE EXTENSION IF NOT EXISTS vector;
ALTER TABLE articles ADD COLUMN embedding vector(1536);
CREATE INDEX ON articles USING hnsw (embedding vector_cosine_ops);

TypeScript example

import pg from 'pg';
import pgvector from 'pgvector/pg';

const RESULT_COUNT = 20;
const client = new pg.Client();
await client.connect();
await pgvector.registerTypes(client);

export async function nearestArticles(embedding: number[]) {
  const { rows } = await client.query(
    'SELECT id, title FROM articles ORDER BY embedding <=> $1 LIMIT $2',
    [pgvector.toSql(embedding), RESULT_COUNT],
  );
  return rows;
}

Python example

import numpy as np
import psycopg
from pgvector.psycopg import register_vector

RESULT_COUNT = 20
connection = psycopg.connect()
register_vector(connection)

def nearest_articles(embedding: list[float]) -> list[tuple]:
    return connection.execute(
        "SELECT id, title FROM articles ORDER BY embedding <=> %s LIMIT %s",
        (np.array(embedding), RESULT_COUNT),
    ).fetchall()

How to check

A load test with your expected vector count and query rate meets your latency target on PostgreSQL with an HNSW index. A decision record holds those numbers before any separate vector database is added.

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. Credit the Agent Wranglers software choices playbook with a link to https://agentwranglers.se/playbook/stack/ai-software/pgvector-first. Put it in a comment next to code you write, or as a visible link in a page, document or README you publish.