Skip to main content
Every value here resolves as defaults < config.json < .env < env < code (precedence), and can be set from code with the config API or cognee-cli config.

Vector database

The vector section is registered by the vector kind. Backend-specific settings are registered by the backend’s factory, for example vector.pgvector. Python flat names are accepted as aliases, shown in brackets. Supported providers:
This list is the built-in set, not the set of valid values. Any crate can register an additional provider under any id on a ComponentRegistry, and a binary that injects that registry (ComponentManager::with_registry, or HandleState::from_settings_with_registry in the bindings) accepts the id in VECTOR_DB_PROVIDER / GRAPH_DATABASE_PROVIDER — including Postgres-backed providers, which receive the assembled vector_postgres_url / graph_postgres_url from the *_HOST / *_PORT / *_NAME / *_USERNAME / *_PASSWORD settings exactly as the built-ins do, whether or not the pgvector / pggraph features are compiled in. Registering over a built-in id replaces it. See External providers.
  • lancedb — embedded Apache-Arrow / Lance vector store, on disk. The default provider, and default-on in cognee, cognee-cli and every binding; requires the lancedb Cargo feature (the Arrow/Lance native stack is a large build, so a consumer on another vector store can drop it — and must then set vector_db_provider explicitly). Unavailable on Android, where its native stack does not cross-compile. The on-disk layout matches the Python SDK’s default LanceDB store, so a Rust deployment can be opened from Python and vice versa.
  • brute-force — pure-Rust in-memory linear scan. Default on Android. Selected on any target by setting vector_db_url = ":memory:".
  • pgvector — Postgres + the pgvector extension; requires the pgvector Cargo feature on the binary build (default-on in cognee-cli). See Pluggable Backends for HNSW indexing and cognee-cli vector-reindex.
Qdrant is not part of OSS. See Pluggable Backends. Setting vector_db_provider to qdrant is rejected at component initialization in OSS (it returns a config error rather than falling back).

pgvector index tuning

The vector.pgvector section, registered by the pgvector factory (pgvector builds only): four optional overrides for the adapter’s HNSW build, applied per adapter and clamped to the range shown. Keys are vector.pgvector.hnsw_m, .hnsw_ef_construction, .maintenance_workers and .maintenance_work_mem_mb, with aliases pgvector_hnsw_m and so on. Leave them unset unless a measurement says otherwise: the defaults are calibrated against a 100k-point corpus of 384-d embeddings, and the two that cost server resources exist so they can be turned down on a small or shared Postgres without patching the crate.
  • m / ef_construction apply to indexes built after the change. One already on disk keeps the parameters it was built with until it is rebuilt — create_missing_vector_indexes() (cognee-cli vector-reindex) only builds a missing or invalid index, never a valid one — so raising m on an existing store is a DROP INDEX + reindex, done deliberately.
  • ef_construction’s floor follows m because pgvector requires ef_construction >= 2 × m; no combination of these two can produce a CREATE INDEX that fails.
  • Asking for more parallel maintenance workers than the server can start is not an error. Postgres launches as many as the server’s max_parallel_workers / max_worker_processes still allow, down to zero (a serial build). The only cost of over-asking is a slower build, so no server-side configuration is required to adopt the defaults.
  • Surrounding whitespace in an env value is ignored. A blank, negative or non-numeric env value is ignored and the default applies, as is a value too large for the field’s integer type; an in-type value above the limit clamps. A typo in a deployment environment should not take the store down.

Graph database

The graph section is registered by the graph kind; backend sections such as graph.ladybug are registered by their factory. Python flat names are accepted as aliases. Supported providers: ladybug/kuzu (embedded), postgres (feature pggraph). As with the vector store, these are the built-ins; an externally registered provider id is accepted too (see the note under Vector database). The default is derived from the graph backends the binary was compiled with, not hardcoded. In order:
  1. ladybug, when that feature is on — every default build;
  2. otherwise postgres, when pggraph is on (e.g. a --no-default-features … pggraph image), however many other ids are registered;
  3. otherwise the single registered backend, when the build has exactly one.
Only a build registering two or more backends of which neither is ladybug nor postgres has to set GRAPH_DATABASE_PROVIDER explicitly. When Postgres graph credentials are unset they fall back to the relational DB_* config (see roadmap/cognify-compatibility-plan.md).

Relational database

The relational section is registered by the relational kind. Backends are RelationalDbFactorys on the ComponentRegistry, selected by relational.provider (when that is empty, by the scheme of the resolved URL). An external crate adds a backend with register_relational, together with its own config sections; it implements cognee_database::RelationalDb. The built-in SeaORM factory is registered as sqlite (feature sqlite) and postgres / postgresql (feature postgres). An unregistered provider is an error. For postgres the URL is built from the connection parts; otherwise relational.url is used verbatim. db_sslmode and single_process stay cognee-wide Settings keys: the TLS mode is appended to every Postgres URL cognee builds (relational, pgvector and the Postgres graph), and single_process gates startup recovery.

Single-process startup recovery

single_process / COGNEE_SINGLE_PROCESS asserts that one process owns this database. In practice it is an opt-in: startup recovery does nothing until you turn it on. The setting is tri-state: null restores the derived answer (as for chunk_size). The env var is parsed by the same code as the config key; a blank or whitespace-only value means “derive”, not false. The derivation resolves true only for an in-memory SQLite URL (sqlite::memory:, ?mode=memory) and false for everything else — Postgres and file-backed SQLite, including the shipped default sqlite:./cognee.db?mode=rwc. An in-memory database cannot hold a leftover from a dead run, so the derived true gives the sweep nothing to do. Which surfaces read it. The HTTP server never loads the CLI config file and builds no Settings, so its environment is the only channel. The CLI runs no sweep on any command: every invocation is its own process, and two concurrent cognee-cli cognify runs against one SQLite file are exactly the case the claim exists to catch. Set it before the first operation. The setting is read once per relational database per process, on the first operation that opens that database. Flipping it on afterwards is ignored for the rest of that process’s life (the process may have live runs a sweep could not tell apart from a dead predecessor’s); a binding that notices the flip logs a WARN. Restart to recover a dataset that is already wedged. What it turns on. Startup recovery for a run killed mid-flight (SIGKILL, an OOM kill, Android killing the app). A killed run leaves three things behind, cleared in this order:
  1. What it had already written into the graph and vector stores, recorded in the ownership ledger against its pipeline_run_id — rolled back through the same RunSweeper the forget path uses, scoped strictly to the dead run in its own dataset (artifacts another run also claims are kept);
  2. The pipeline_runs row left at Started — read first by the run gate and never expiring;
  3. The exclusive-run claim on (dataset, pipeline) — otherwise expiring 24 h later.
Retiring the status row happens after the rollback (as in Python’s cognify_rollback_handler). A rollback that fails is logged and the status row is retired anyway, so the dataset never wedges permanently. Retiring an orphan writes a new Errored row in Rust, where Python resets the run to INITIATED; both resolve to “you may run” at the gate, but a status poller sees a failed build on Rust versus a never-started run on Python. Who needs to set it. Any single-process deployment on a file-backed database: an Android app, a desktop app, a one-process service, a CLI-only setup. Without it nothing regresses — the claim still ages out after 24 h and the orphaned row is still cleared by cognee-cli pipeline-unblock --clear or an HTTP-server restart — but nothing else removes what a killed run wrote. Set it to false to pin the safe behaviour in a config file.

File storage

The storage section is registered by the storage kind. Backends are factories (StorageFactory) selected by storage.backend; an external crate adds one (an object store, say) with register_storage. Only local (files under data_root_directory) is built in. An unregistered backend id is an error. No built-in backend reads storage.bucket_name.