Basic Memory
Local

Postgres and Milvus

Run Basic Memory on local Postgres and use pgvector, Milvus Lite, Milvus, or Zilliz Cloud for semantic vectors.

SQLite remains the simplest local backend. Use this guide when you need to exercise the Postgres runtime or move a Postgres deployment's vector storage from pgvector to Milvus.

Start local Postgres

Basic Memory's Postgres backend requires the pgvector extension even when Milvus will own semantic vectors. Create docker-compose-postgres.yml with the same local service used by the Basic Memory repository:

docker-compose-postgres.yml
services:
  postgres:
    image: pgvector/pgvector:pg17
    container_name: basic-memory-postgres
    environment:
      POSTGRES_DB: basic_memory
      POSTGRES_USER: basic_memory_user
      POSTGRES_PASSWORD: dev_password
    ports:
      - "5433:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U basic_memory_user -d basic_memory"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  postgres_data:

Start the database:

docker compose -f docker-compose-postgres.yml up -d
docker compose -f docker-compose-postgres.yml ps

Point Basic Memory at it before starting the MCP server or running a CLI command:

export BASIC_MEMORY_DATABASE_BACKEND=postgres
export BASIC_MEMORY_DATABASE_URL='postgresql+asyncpg://basic_memory_user:dev_password@localhost:5433/basic_memory'

bm status

The first startup applies migrations and seeds the default project automatically. The credentials above are for a private local development database only; choose real credentials and network controls for any shared deployment.

Plain postgres:17 does not include pgvector. Use the pgvector/pgvector:pg17 image or run CREATE EXTENSION IF NOT EXISTS vector; on an existing Postgres server before Basic Memory migrates it.

Use the default pgvector index

Postgres uses pgvector unless you change semantic_vector_index. Build embeddings for already indexed notes with:

bm reindex --embeddings

SQLite ignores semantic_vector_index and continues to use sqlite-vec.

Install Milvus support

Install Basic Memory with the optional Milvus dependency:

uv tool install 'basic-memory[milvus]'

The extra supports Milvus Lite on macOS and Linux and remote Milvus or Zilliz Cloud on every supported platform. Windows cannot run Milvus Lite but can connect to a remote deployment.

Configure Milvus Lite

Create the parent directory first, then use an absolute URI ending in .db:

mkdir -p "$PWD/.basic-memory-milvus"
bm config set semantic_vector_index milvus
bm config set milvus_uri "$PWD/.basic-memory-milvus/basic-memory.db"

Despite the suffix, Milvus Lite creates a directory tree at that path, including collections/, databases/, and LOCK; it does not create one database file. Pymilvus rejects a URI without the .db suffix or a URI whose parent directory does not already exist.

milvus_database is ignored by Milvus Lite because Lite does not support named databases. Leave its default value in place.

Connect remote Milvus or Zilliz

bm config set semantic_vector_index milvus
bm config set milvus_uri http://localhost:19530
bm config set milvus_token root:Milvus

For Zilliz Cloud, set its endpoint and token instead. milvus_timeout_seconds applies to every client operation and defaults to 30 seconds. Collections reload across processes, so a restart reuses an existing compatible collection.

Reindex after every index switch

Run an incremental embedding rebuild immediately after changing semantic_vector_index:

bm reindex --embeddings

The incremental rebuild is sufficient; --full is not required. Until the configured index has ready rows:

  • vector search returns no results;
  • hybrid search quietly serves full-text results only; and
  • bm reindex --embeddings reports which index it populated and exits nonzero on failure.

Hands-on verification found identical vector rankings and scores to four decimal places across sqlite-vec, pgvector, and Milvus Lite on the same corpus. Basic Memory also refuses dimension mismatches, reports a missing Milvus extra directly, honors the configured timeout, and reloads collections after restart.

Switch indexes safely

Vector-index ownership is fail-closed. If a switch or switch-back finds manifest rows owned by another index, Basic Memory refuses to mutate them instead of guessing which vector store is authoritative.

  1. Restore the previously configured index if a premature switch raises SemanticVectorIndexExtensionError.
  2. Remove the current index's project-scoped vectors and the corresponding vector-manifest rows while that index is still configured.
  3. Change semantic_vector_index.
  4. Run bm reindex --embeddings and confirm it exits successfully.

There is no general cleanup command yet. Treat manual vector-store and manifest cleanup as an operator procedure and back up the database first.

Switching from pgvector to Milvus leaves the old rows in Postgres's search_vector_embeddings projection. They are not used by the Milvus search path, but they continue to consume disk until you remove them manually. Do not delete them until the Milvus rebuild is successful and you have decided not to switch back using that projection.

Stop local Postgres

docker compose -f docker-compose-postgres.yml down

Add --volumes only when you intentionally want to delete the local database volume.