Skip to main content
Vector stores hold embeddings for semantic similarity search. They enable Cognee to find conceptually related content based on meaning rather than exact text matches.
New to configuration?See the Setup Configuration Overview for the complete workflow:install extras → create .env → choose providers → handle pruning.For a complete, copy-paste .env block that combines this layer with a relational and a graph store, see Store Configurations.

Supported Providers

Cognee supports multiple vector store options through built-in providers and community-maintained adapters:

Configuration

Community adapters must still be installed and registered in your application startup code before Cognee can use their provider value.
Use this shape for LanceDB.

Setup Guides

LanceDB is file-based and requires no additional setup. It’s perfect for local development and single-user scenarios.
Installation: LanceDB is included by default with Cognee. No additional installation required.Data Location: Vectors are stored in a local directory. Defaults under the Cognee system path if VECTOR_DB_URL is empty.
PGVector stores vectors inside your Postgres database using the pgvector extension.
Installation: Install the Postgres extras:
Docker Setup: Use the built-in Postgres with pgvector:
Note: If using your own Postgres, ensure CREATE EXTENSION IF NOT EXISTS vector; is available in the target database.For Neon Postgres, run that extension statement once in the Neon database where Cognee stores vectors. Neon still uses the regular Cognee pgvector provider; configure the relational DB_* values and DATABASE_CONNECT_ARGS as described in Relational Databases, then set VECTOR_DB_PROVIDER="pgvector".When backend access control is enabled, configure the explicit VECTOR_DB_HOST, VECTOR_DB_PORT, VECTOR_DB_NAME, VECTOR_DB_USERNAME, and VECTOR_DB_PASSWORD values instead of relying on the relational DB fallback.Dedicated vs shared database. PGVector either gets its own connection engine or borrows the relational one, and which of the two you get decides whether the vector store can be pruned on its own:
If you previously ran with ENABLE_BACKEND_ACCESS_CONTROL="false" and a fully configured VECTOR_DB_* block whose VECTOR_DB_NAME differed from DB_NAME, Cognee wrote vectors into the relational database and now reads and writes the dedicated one — so existing vectors become invisible. See the changelog for the upgrade options.
Turso stores vectors in a local database file on Turso, the Rust rewrite of SQLite. Each collection is one table, and similarity search is an exact cosine-distance scan (there is no approximate index).
Installation: Install the Turso extra:
This pulls in pyturso. If the extra is missing, selecting VECTOR_DB_PROVIDER="turso" raises an ImportError at engine creation with the install hint.Local files only: Remote Turso databases are not supported. A libsql://, http(s)://, or ws(s):// value in VECTOR_DB_URL raises an error at engine creation, and VECTOR_DB_KEY is ignored. Any other value is treated as a local file path.Journal mode: TURSO_JOURNAL_MODE is wal by default. Set it to mvcc to let concurrent writers commit in parallel; see Turso Local for the trade-offs.Multi-user mode: Setting VECTOR_DB_PROVIDER="turso" automatically selects the turso dataset database handler (you do not need to set VECTOR_DATASET_DATABASE_HANDLER yourself). With ENABLE_BACKEND_ACCESS_CONTROL=True, each dataset gets its own Turso database file named {dataset_id}.turso.db under <SYSTEM_ROOT_DIRECTORY>/databases/{user_id}/. Deleting a dataset evicts its cached engine and removes that file.
Qdrant requires a running instance of the Qdrant server.
Installation: Since Qdrant is a community adapter, you have to install the community package:
Configuration: To make sure Cognee uses Qdrant, you have to register it beforehand with the following line:
For more details on setting up Qdrant, visit the more detailed description of this adapter.Docker Setup: Start the Qdrant service:
Access: Default port is 6333 for the database, and you can access the Qdrant dashboard at “localhost:6333/dashboard”.
Redis can be used as a vector store through the Redis Search module, providing fast vector similarity search capabilities.
Installation: Since Redis is a community adapter, you have to install the community package:
Configuration: To make sure Cognee uses Redis, you have to register it beforehand with the following line:
You can also configure Redis programmatically:
For more details on setting up Redis, visit the more detailed description of this adapter.Docker Setup: Start a Redis instance with Search module enabled:
Or use Redis Cloud with the Search module enabled: Redis CloudConnection URL Examples:
  • Local: redis://localhost:6379
  • With authentication: redis://user:password@localhost:6379
  • With SSL: rediss://localhost:6380
ChromaDB support is optional and may not be installed in your Cognee environment by default.
Installation: Install ChromaDB support before configuring VECTOR_DB_PROVIDER=chromadb:
If you are using ChromaDB through a community adapter package instead of a Cognee extra, install that adapter package and call its register() function before running Cognee vector operations.Docker Setup: Start a ChromaDB server:
FalkorDB can serve as both graph and vector store, providing a hybrid solution.
Installation: Since FalkorDB is a community adapter, you have to install the community package:
Configuration: To make sure Cognee uses FalkorDB, you have to register it beforehand with the following line:
For more details on setting up FalkorDB, visit the more detailed description of this adapter.Docker Setup: Start the FalkorDB service:
Access: Default ports are 6379 (DB) and 3000 (UI).
Use Amazon Neptune Analytics as a hybrid vector + graph backend.
Installation: Install Neptune extras:
Note: URL must start with neptune-graph:// and AWS credentials should be configured via environment variables or AWS SDK.Access control must be off. Cognee registers no per-dataset database handler for Neptune Analytics, so with ENABLE_BACKEND_ACCESS_CONTROL left at its default the handler stays lancedb and the first dataset access raises The selected vector dataset to database handler does not work with the configured vector database provider.

Important Considerations

Ensure EMBEDDING_DIMENSIONS matches your vector store collection/table schemas:
  • PGVector column size
  • LanceDB Vector size
  • ChromaDB collection schema
A collection’s vector width is fixed when the collection is created, so all of a dataset’s vectors must come from one embedding model. Changing dimensions requires recreating collections.Cognee records the model per dataset and checks it once. In multi-user mode (ENABLE_BACKEND_ACCESS_CONTROL="true", the default) every dataset has a registry row, and Cognee writes the resolved embedding model and its width into that row’s vector_database_connection_info JSON as two keys:
The record is written when the row is created — that is, when the dataset’s databases are first provisioned — and the model is resolved exactly as the embedding engine resolves it, so a keyless install records the local fastembed model it actually embeds with rather than the stock config default.The comparison then happens once per dataset-context entry, against the already-loaded row and after the dataset’s vector configuration is bound. There is no extra call to the vector store on ordinary operations. Only the recorded width is compared, not the model name, so a swap to a different model of the same width passes the check — the vectors stay in place and recall degrades silently, as it did before.On a mismatch you get a 409. If the configured model’s width differs from the recorded one, Cognee raises EmbeddingDimensionMismatchError (HTTP 409) before any write or query reaches the store, naming the dataset, both models, and both widths:
Remediation is either of:
  • Set EMBEDDING_MODEL back to the model that built the dataset, to keep using it as is.
  • To move the dataset to the new model: restore the old EMBEDDING_MODEL, delete the dataset (await cognee.forget(dataset="...") or cognee-cli forget), then set the new model and ingest again. Deleting enters the same dataset context, so it raises the same 409 while the mismatch stands — the old value has to be back before forget will run. A full await cognee.prune.prune_system() goes through the store handlers instead of the dataset context and is not affected.
This replaces the store-level failure — an Arrow cast error or expected N dimensions, not M, which named neither the dataset nor the model — for datasets that carry the record. See How do I determine EMBEDDING_DIMENSIONS? for picking the value in the first place.Datasets created before the record existed are completed once from the store. When a row carries no recorded width, Cognee asks the vector store for the width already in it — get_stored_vector_size(), implemented by LanceDB and PGVector — and records that width permanently (with embedding_model left null, since the model that built it is unknown; the error then reports it as “an earlier embedding model”). An empty store adopts the configured model instead, and a provider that does not implement the method is left to the store’s own errors. If such a store holds two widths — the state a live EMBEDDING_MODEL change used to leave behind, where old collections keep the old width and new ones get the new one — the width most collections use is reported, the smaller one on a tie, and a warning is logged naming every width found. Re-embed that dataset to make it consistent.Single-user mode is unchanged. With ENABLE_BACKEND_ACCESS_CONTROL="false" there is no per-dataset registry row, nothing is recorded, and an embedding-model change still surfaces as the vector store’s own dimension error on first write.Pruning clears the record. A vector prune that keeps the registry rows (await cognee.prune.prune_system(metadata=False)) deletes the vectors the record described, so it also drops the two recorded keys; the default await cognee.prune.prune_system() additionally drops the relational database and the rows with it. Either way the next use of each dataset records whatever model builds it anew, so prune-and-re-ingest remains a valid way to move a deployment to a new embedding model — and unlike forget, it is not blocked by the mismatch it resolves.
PGVector does not use a single embeddings table. Cognee creates one table per indexed field, named {DataPointType}_{field} — for example DocumentChunk_text, Entity_name, EntityType_name, and TextSummary_text. Each of these collection tables has exactly three columns:When PGVector shares the relational Postgres database, these collection tables live in the same schema as the snake_case relational metadata and provenance tables (data, datasets, dataset_data, nodes, and edges). If you configure PGVector with separate VECTOR_DB_* settings, the collection tables live in that vector database instead. When using the Postgres graph store, graph data is stored in graph_node and graph_edge.Cognee distinguishes vector collections by their PascalCase first letter. Text content is stored in the JSON payload and in TEXT columns; there are no fixed-width varchar(255) columns (the relational provenance nodes.label / nodes.type columns were migrated from varchar(255) to TEXT).
Every upsert into a LanceDB table appends a new fragment and leaves the superseded rows and table versions on disk, and LanceDB never reclaims them on its own. Cognee therefore compacts local LanceDB stores automatically. Nothing needs to be configured or deployed.When it runs. Once per dataset at the end of every successful cognify() run, and so after every remember() that cognifies. A pass has two steps:
  1. Merge small fragments into larger ones (up to 20,000 rows each). This step holds the vector write lock, because its commit would conflict with a concurrent upsert or delete.
  2. Prune superseded table versions. A version is deleted only after the version that replaced it is older than a 300-second retention window, so a reader that opened a table a moment ago keeps its snapshot. Pruning commits nothing and does not take the write lock, so writers are never blocked by it.
Each pass is bounded. One pass runs at most 4 compaction tasks and removes at most 1,000 old versions, counted across all tables of the store, not per table. Tables written since the last pass go first, and a rotating cursor moves through the rest so no table is skipped forever. A store with a large backlog therefore shrinks over several cognify runs instead of stalling one. These limits are fixed in code; there are no environment variables for them.Space from a pass is freed later. Files a pass replaces can only be deleted once the retention window has passed, so the next cognify() on that store reclaims them. Nothing prunes in the background: pruning runs only inside a pass, so no prune can outlive the adapter or run while it closes.Both LanceDB modes are covered. With VECTOR_DB_SUBPROCESS_ENABLED=true (the default) the two steps run inside the existing LanceDB subprocess worker. With it off they run in a thread.When it does not run:
  • Remote stores (db://, http://, https://, s3://, gs://, az://) are skipped, because there every rewrite is network transfer and cleanup means thousands of object deletes.
  • pylance and lancedb do not match. Compaction is turned off for the adapter’s lifetime. See LanceDB compaction turned off below.
  • A pass is already running on the same adapter. The second one returns at once with {"skipped": "in_progress"} instead of waiting.
It never fails your run. Compaction is best-effort: an error is logged, and for a single table it is recorded in the pass’s stats while the other tables continue. The cognify run that triggered it still succeeds.

Troubleshooting

With ENABLE_BACKEND_ACCESS_CONTROL="false", a vector-only prune against a PGVector store that shares the relational Postgres database fails with:
Cognee refuses rather than dropping every table in a database that also holds data, datasets, dataset_data, users, and permissions. Because cognee.prune.prune_system() defaults to metadata=False, the bare call is the one that hits this.Either delete the shared database as a whole, which also removes datasets, data records, users and permissions:
Or move the vector store into a dedicated database by setting all five VECTOR_DB_* values with a distinct VECTOR_DB_NAME, per the table in the PGVector setup section above. Nothing is deleted when the error is raised — the vector step runs before graph deletion so the refusal aborts the prune first.
This issue is most commonly reported with LanceDB-backed search workloads.VECTOR_DB_SUBPROCESS_ENABLED defaults to true. In high-fanout searches — for example, many queries across many datasets — this can create a large number of OS subprocesses. On macOS, that can quickly hit the default file descriptor limit (ulimit -n, often 256) and surface as:
Because the exception often appears inside LanceDB internals, it may not be obvious that the underlying issue is subprocess and file-descriptor exhaustion rather than a LanceDB data problem.If this happens:
And raise the shell limit before starting Cognee:
This is especially relevant for audit-style or multi-dataset search runs where Cognee fans queries out across several datasets in parallel.
When VECTOR_DB_SUBPROCESS_ENABLED is true, concurrent async RPCs to the LanceDB subprocess run in parallel rather than serializing behind a single session lock. Each request carries its own id and is routed back to its own waiter, so concurrent add and search operations no longer queue behind one another.SUBPROCESS_WORKER_MAX_INFLIGHT (default 16) bounds how many async operations a worker runs at once, keeping the worker’s memory footprint predictable. The value must be > 0; a zero or negative value fails worker initialization with a ValueError rather than silently degrading. Raise it for higher concurrency (for example, SUBPROCESS_WORKER_MAX_INFLIGHT=64), or set a large value to effectively remove the cap.A per-call timeout or cancellation now resolves only that individual call and leaves the subprocess session running for other in-flight and future calls. The session is torn down only on genuine session-ending events (worker crash, shutdown, or respawn), which propagate a SubprocessTransportError to any calls still pending. Synchronous calls (such as the Kuzu graph backend) are unaffected and continue to run serially.Subprocess engines are also no longer closed the moment a dataset context exits. SUBPROCESS_IDLE_TTL_SECONDS (default 600) keeps an idle engine warm, and a background reaper thread closes it only after a full TTL with no use — so repeated or interactive queries against the same dataset reuse the live worker instead of paying for a close plus a respawn. Datasets with an active dataset-queue slot are skipped by the reaper, and non-subprocess engines (PGVector and other remote stores) are never reaped.The trade-off: a kept-warm worker holds its memory and its PID (and, for the graph store’s embedded Kuzu/Ladybug worker, its database file lock — LanceDB takes no exclusive file lock) for up to the TTL after its last use, with the total number of retained idle workers still bounded by DATABASE_MAX_LRU_CACHE_SIZE. Lower the TTL, or set SUBPROCESS_IDLE_TTL_SECONDS=0 to close engines at each dataset-context exit as before, if you are memory-tight or need locks released promptly. See Subprocess engine teardown coordination for the full lifecycle.
Cognee’s automatic LanceDB compaction uses pylance to rewrite the tables lancedb writes, so the two must be on the same Lance core release line. If they are not, compaction turns itself off for the lifetime of the adapter and logs one of these warnings:
Ingestion and search keep working, but the store is no longer compacted and keeps growing on disk. To fix it, install the pair Cognee pins in pyproject.toml (currently lancedb>=0.39.0,<0.40.0 and pylance>=12.0.0,<12.1.0), for example by reinstalling Cognee instead of upgrading pylance or lancedb on its own, then restart the process.Other log lines from compaction:
  • Vector store compaction: N collection(s), fragments a -> b, ...: the summary of one pass, including how many tasks and versions were left for later runs. It is logged at info when the pass did work and at debug otherwise.
  • Vector store compaction skipped: ... and Compaction skipped for collection '...': warnings for a pass, or one table in it, that failed. They are not fatal, and the next cognify run tries again.

Community-Maintained Providers

Additional vector stores are available through community-maintained adapters:
  • Qdrant — Vector search engine with cloud and self-hosted options
  • Redis — Fast vector similarity search
  • FalkorDB — Hybrid vector and graph store
  • Pinecone — Managed vector database (requires separate install + registration)
  • Turbopuffer — High-performance vector database
  • Milvus, Weaviate, and more — See all community adapters

Notes

  • Embedding Integration: Vector stores use your embedding engine from the Embeddings section
  • Dimension Matching: Keep EMBEDDING_DIMENSIONS consistent between embedding provider and vector store
  • Performance: Local providers (LanceDB) are simpler but cloud providers offer better scalability

Embedding Providers

Configure embedding providers for vector generation

Graph Stores

Set up graph databases for knowledge graphs

Overview

Return to setup configuration overview