Skip to main content
Cognee keeps memory in three stores: a relational database for metadata, a vector store for embeddings, and a graph store for entities and their relationships. Each is configured on its own, so a working setup is always a combination — and the combination is what the reference pages leave to you to assemble. This page closes that gap. Every stack below is one complete .env block: paste it, fill in your LLM API key, install the listed extras, start the listed server, and run the same verification script. Nothing is left to look up on another page. Before you start:
When you switch any store — or change embedding model or dimensions — run cognee.prune.prune_system(metadata=True) once before your next cognify() / remember(). Collections written under the previous embedding dimensions are not compatible with the new ones.

What you get by default

With no store variables set at all, Cognee runs entirely on embedded, file-based stores. No server, no extras, nothing to install: SYSTEM_ROOT_DIRECTORY defaults to a folder inside the installed package, which is usually your virtual environment — pin it to an absolute path in your project if you want the stores to survive a reinstall. Because per-dataset isolation is on by default, the graph and vector layers write one file per dataset (<user_id>/<dataset_id>.lbug and .lance.db) rather than the single cognee_graph_ladybug / cognee.lancedb files you get with it switched off.
ladybug and kuzu are the same embedded engine — Ladybug is the renamed Kuzu engine, and either provider value works. They do not share a file: the graph file is named cognee_graph_<provider>, so switching the value points Cognee at a different (initially empty) graph. The exception is upgrades — if a cognee_graph_kuzu file already exists, ladybug keeps using it instead of starting fresh.

Choose a stack

The docker compose commands below come from the docker-compose.yml in the cognee repository — clone it, or point the blocks at your own instances.

The stacks

Embedded (default)

Everything file-based and in-process. This is what you get with no store configuration at all; the block is written out so you can see which variables the other stacks are overriding. Install:
Servers: none. .env configuration:
The embedded graph store uses file-based locking and is not meant to be shared between processes or agents running at once. For concurrent access, use Neo4j or the Postgres graph store below.

One Postgres for everything

Relational metadata, vectors (pgvector), and graph state all in a single Postgres database. Install:
Server:
The bundled service is the pgvector/pgvector:pg17 image on port 5432, with user cognee, password cognee, and database cognee_db already created. Cognee issues CREATE EXTENSION IF NOT EXISTS vector itself, so nothing else needs preparing. .env configuration:
The Postgres graph store is a demo feature — it stores nodes and edges in graph_node / graph_edge tables and does not support the Cypher search types. Postgres remains a good production choice for the relational and vector layers; for the graph layer in production use Neo4j (next stack) or the licensed Postgres graph adapter — book a call at cognee.ai. See Graph StoresPostgres.
The VECTOR_DB_* and GRAPH_DATABASE_* credentials repeat the relational ones on purpose. Cognee can fall back to DB_* for both layers, but only when multi-user access control is off — with it on (the default), the per-dataset engines need their own explicit values and fail without them. Spelling them out keeps the block working either way.

Postgres and Neo4j

Postgres for metadata and vectors, Neo4j for the graph. This is the usual production shape. Install:
Servers:
The bundled Neo4j service is neo4j:5.26 with the APOC and GDS plugins enabled, reachable at bolt://localhost:7687 with user neo4j and password pleaseletmein. .env configuration:
APOC is what gives Cognee’s nodes their type-specific labels in Neo4j Browser. The bundled Docker service includes it; a self-hosted server needs the APOC plugin installed.
For Neo4j AuraDB, keep everything above and swap the connection line for the neo4j+s:// URI from your Aura console — see Graph StoresNeo4j Aura (Cloud):

Neo4j graph with embedded rest

Neo4j for the graph, embedded defaults for everything else. The lightest way to get a browsable graph without running Postgres. Install:
Server:
.env configuration:
Once a run finishes, open http://localhost:7474, log in with the same credentials, and inspect the graph. Neo4j Desktop works the same way — point GRAPH_DATABASE_PASSWORD at your Desktop database’s password, and install APOC from the plugins panel. See Graph StoresNeo4j Desktop (Local Development).

Turso (libSQL)

All three layers on libSQL. A libSQL file is a SQLite file, so this runs embedded with no server, and the relational layer can later sync against a hosted Turso primary. Install:
Servers: none for the embedded setup. .env configuration:
To point the relational layer at a hosted Turso database, add the remote credentials — Cognee then reads and writes a local replica and syncs it in the background:
Remote mode is not available on all three layers. The vector layer accepts a libsql:// URL with VECTOR_DB_KEY — see Vector StoresTurso (libSQL) — and the graph layer is local-file only, so setting GRAPH_DATABASE_KEY raises an explicit “not supported yet” error.

Verify your stack

Every block above is checked the same way. Save the .env in your project root, then run this from the same directory:
A working stack prints a graph_completion answer naming the three stores. If it prints an empty list, or raises before it gets there, work through Troubleshooting below. To confirm which providers were actually resolved — useful when a variable is not being picked up — print the resolved configuration first:

Mix your own

The five stacks are combinations, not a fixed menu — any relational store works with any vector store and any graph store. These are the values Cognee supports out of the box: Two rules cover most of what can go wrong when you assemble your own:
  • Do not set the *_DATASET_DATABASE_HANDLER variables. Cognee derives the per-dataset handler from the provider (pgvectorpgvector, neo4jneo4j, postgres_demopostgres_graph, tursoturso_graph). Set them only to pick a different isolation strategy, such as pgvector_shared and postgres_graph_shared (one schema per dataset instead of one database per dataset, which needs only CREATE SCHEMA rights) or neo4j_community. A handler that does not match its provider fails at startup with an explicit EnvironmentError.
  • Check the combination against access control — see the next section.
The AWS options are the ones not shown as a stack above: neptune (graph) and neptune_analytics (hybrid graph + vector) both need pip install "cognee[neptune]", a neptune-graph:// URL, and AWS credentials from the standard SDK chain. See Graph Stores and Vector Stores for their blocks.

Multi-user access control is on by default

Cognee isolates each dataset in its own database unless you turn that off, which is why several blocks above carry explicit per-layer credentials or an ENABLE_BACKEND_ACCESS_CONTROL="false" line. What changes with it on:

Troubleshooting

Neo4j Community — including the bundled docker compose --profile neo4j service — allows exactly one database per server, but Cognee’s default access-control mode wants one per dataset. Pick one of:
  1. Turn per-dataset isolation off (what the Neo4j blocks above do): ENABLE_BACKEND_ACCESS_CONTROL="false". All datasets then share one graph database.
  2. Keep isolation on Community with GRAPH_DATASET_DATABASE_HANDLER="neo4j_community", which runs one Neo4j container per dataset and needs a reachable Docker daemon. See Neo4j Community handler.
  3. Use Neo4j Enterprise or AuraDB, where CREATE DATABASE is available and the default mode works unchanged.
Port 123 is the unset default for GRAPH_DATABASE_PORT. With access control on (the default), the postgres_demo graph store does not inherit the relational DB_* settings — it needs its own credentials. Add the full GRAPH_DATABASE_HOST / PORT / NAME / USERNAME / PASSWORD set, as in the One Postgres block, or set ENABLE_BACKEND_ACCESS_CONTROL="false" to use the fallback.The related warning below is the same mechanism in its working case — the fallback ran, and naming the values explicitly silences it:
Vector collections are written for a specific embedding model and dimension count. Switching store, embedding model, or EMBEDDING_DIMENSIONS leaves collections behind that no longer match, which surfaces as empty recalls or dimension-mismatch errors. Clear them once:
Then re-run your ingestion. Note this deletes everything Cognee has stored — on a shared server, point the new stack at a different database instead.
Cognee creates its tables, but not the database named in DB_NAME — for Postgres that must already exist. The bundled Docker service creates cognee_db for you; on your own server, create it once:
See Relational Databases for the related DatabaseNotCreatedError case.
localhost inside a container is the container itself. When Cognee runs in a container and the store runs on your host, use host.docker.internal:
When both run under the same Compose project, use the service names instead — postgres and neo4j.
Cognee reads .env from the directory the process starts in, so run your script from the directory holding the file, or set the variables in the process environment instead. Values in .env are applied with override=True, so a .env entry wins over a variable already exported in your shell — if an old exported value is not taking effect, that is why.To see what Cognee actually resolved, print the configuration with the snippet in Verify your stack.

Beyond the built-in stores

Qdrant, Redis, Pinecone, Turbopuffer, Milvus, Weaviate, FalkorDB, and Memgraph are available as community-maintained adapters. They install as separate packages and must be registered in your startup code before their provider value works — see Community-Maintained Adapters. If your backend is on neither list, you can write a custom adapter for the vector or graph layer: implement the adapter class and register it in your startup code with use_vector_adapter("your_name", YourAdapter) or use_graph_adapter(...), and the registered name then works as a VECTOR_DB_PROVIDER / GRAPH_DATABASE_PROVIDER value like any built-in one. With access control on, the adapter also needs its own dataset database handler registered via use_dataset_database_handler(...) — otherwise run it with ENABLE_BACKEND_ACCESS_CONTROL="false". The walkthroughs are Vector Database Integration and Graph Database Integration. The relational layer has no registration hook — it is limited to the built-in sqlite, postgres, and turso.

Relational Databases

Pooling, SSL, managed Postgres, and migration sources

Vector Stores

Per-provider settings, table layout, and subprocess tuning

Graph Stores

Every graph backend, including Neptune and remote Kuzu