New to configuration?See the Setup Configuration Overview for the complete workflow:install extras → create
.env → choose providers → handle pruning.Supported Providers
Cognee supports these relational database options:- SQLite — File-based database, works out of the box (default)
- Postgres — Production-ready database for multi-process concurrency
- Turso (libSQL) — A SQLite-compatible drop-in with optional embedded-replica sync for a hosted Turso database
Configuration
Environment Variables
Environment Variables
Set these environment variables in your
.env file:DB_PROVIDER— The database provider (sqlite, postgres, turso)DB_NAME— Database nameDB_HOST— Database host (Postgres only)DB_PORT— Database port (Postgres only)DB_USERNAME— Database username (Postgres only)DB_PASSWORD— Database password (Postgres only)DB_TURSO_URL— Remote Turso database URL, e.g.libsql://<your-db>.turso.io(Turso remote mode only; leave unset for a local libSQL file)DB_TURSO_AUTH_TOKEN— Auth token for the remote Turso database (Turso remote mode only)
Setup Guides
SQLite (Default)
SQLite (Default)
SQLite is file-based and requires no additional setup. It’s perfect for local development and single-user scenarios.Installation: SQLite is included by default with Cognee. No additional installation required.Data Location: Data is stored under the Cognee system directory. You can override the root with
SYSTEM_ROOT_DIRECTORY in your .env file.Postgres
Postgres
Postgres is recommended for production environments, multi-process concurrency, or when you need external hosting.Installation: Install the Postgres extras:Docker Setup: Use the built-in Postgres service:Docker Networking: When running Cognee in Docker and Postgres on your host, set:Migrations: The Cognee API server runs startup migrations during its lifespan startup. For standalone scripts, CI, or deployments where you manage database lifecycle explicitly, run
- .env
- Python
Set the connection in your
.env file:run_startup_migrations before serving traffic — especially the first time you point Cognee at a fresh external Postgres database, or after upgrading the cognee package:Neon Postgres
Neon Postgres
Neon works with Cognee through the normal If your deployment uses If you prefer split settings, map the same connection string into Cognee’s Install Postgres support in the environment where Cognee runs:When using split settings, express Neon’s For PGVector, enable the extension once in the Neon database:Application database vs source database: That source database is separate from Cognee’s application database.Direct vs pooled Neon hosts: use the direct Neon host for setup, schema migrations, and default Cognee connections. The direct hostname does not contain Neon pooled hosts route through PgBouncer and contain Prefer the direct host unless you have a specific need for pooled, high-concurrency application traffic after setup. Run migrations against the direct endpoint only. Neon PgBouncer does not support every session-level operation migrations and maintenance may rely on, and Cognee maintenance operations such as If you use Cognee’s relational database migration features with Neon, keep the application database and migration source database separate. Use direct hosts for both while running migrations:Use a different
postgres relational provider. Cognee can use Neon Postgres for relational metadata, document information, chunks, pgvector storage, and Postgres graph state. Neon requires SSL/TLS for connections.Before configuring Cognee, create a Neon project, branch, database, and role, then copy the connection string from Connection Details in the Neon dashboard. A Neon connection string usually looks like this:DATABASE_URL, set it to the Neon connection string:DB_* variables:?sslmode=require parameter as DATABASE_CONNECT_ARGS='{"ssl": "require"}'. DATABASE_CONNECT_ARGS must be valid JSON. Cognee forwards these arguments to the main relational engine, per-dataset PGVector engines, and the GRAPH_DATABASE_PROVIDER="postgres" graph engine.One Neon database can also back PGVector and the Postgres graph store:DATABASE_URL or the DB_* variables configure Cognee’s own application database. Cognee uses this database for its internal metadata and state. To ingest an external Postgres database as data, pass that source database connection to cognee.add() instead:-pooler:-pooler in the hostname:CREATE DATABASE and DROP DATABASE cannot run through the pooler. If setup or migrations fail on a -pooler host, switch to the direct host and retry.You can verify the same credentials with psql:MIGRATION_DB_NAME unless you intentionally want to migrate Cognee’s own internal tables into the knowledge graph.Turso (libSQL)
Turso (libSQL)
A libSQL database file is a SQLite file, so Turso is a drop-in for the SQLite backend: Cognee talks to it through the same Local / embedded: A libSQL file stored on disk under the Cognee data directory (named by Remote (embedded replica): Set In remote mode Cognee reads and writes a fast local replica through
aiosqlite driver, the same sqlite dialect, and the same sqlite-dialect Alembic migrations. No migration changes are needed when switching between SQLite and Turso.Installation: Install the Turso extra:DB_NAME). This is identical to the SQLite backend:DB_PROVIDER="turso" and point at a hosted Turso database with DB_TURSO_URL and DB_TURSO_AUTH_TOKEN:aiosqlite exactly as in local mode, while libsql-experimental handles embedded-replica sync with the hosted primary. The replica is seeded from the primary before first use, and Cognee attempts a sync after each write within the operation. Seeding and syncing run off the event loop and are best-effort: a slow or unreachable primary is logged and never blocks or breaks a database operation, and the local replica stays usable.The remote write path applies through
aiosqlite; whether libSQL’s sync propagates those writes to the hosted primary depends on the driver’s replica write-capture and should be confirmed against a live Turso database. The local drop-in path is fully exercised offline.Turso is a SQLite-compatible drop-in for Cognee’s core relational backend, but DLT-based ingestion connectors do not yet treat
DB_PROVIDER="turso" the same as sqlite. The main add → cognify → search pipeline is covered; DLT connector support needs a follow-up.Advanced Options
Migration Configuration
Migration Configuration
The See the Relational Database Migration example for a complete walkthrough of migrating schema and data into a knowledge graph.
MIGRATION_DB_* variables point to a source database that you want to extract and migrate into Cognee’s knowledge graph. This is entirely separate from the application database (DB_*) that Cognee uses for its own internal metadata and state.Does the migration DB need to be a different database than the application DB?In practice, use a different database (different
DB_NAME / MIGRATION_DB_NAME) unless you intentionally want to migrate Cognee’s own internal tables into the knowledge graph. They can still live on the same Postgres server as long as they are different databases.- SQLite Source
- Same Postgres Server
- Different Postgres Server
Use this when your source data is in a SQLite file, regardless of what
DB_PROVIDER is set to:Managed Postgres with SSL (connect args)
Managed Postgres with SSL (connect args)
Managed Postgres providers (Neon, RDS/Aurora, Azure Database for PostgreSQL) often require SSL. Pass asyncpg/SQLAlchemy connection arguments through the These connect args are forwarded to Cognee’s main relational engine, per-dataset PGVector engines, and the
DATABASE_CONNECT_ARGS environment variable, which takes a JSON object:GRAPH_DATABASE_PROVIDER="postgres" graph engine. The maintenance engine that runs CREATE/DROP DATABASE also uses the SSL setting. Leaving DATABASE_CONNECT_ARGS unset is a no-op, so in-cluster Postgres needs no change.The maintenance engine talks to Postgres over asyncpg, which expects an ssl key rather than libpq’s sslmode; if you supply sslmode, its value is mapped to asyncpg’s ssl for maintenance operations. For Neon specifically, the maintenance engine also rewrites a -pooler. host to its direct endpoint, because CREATE/DROP DATABASE cannot run through Neon’s PgBouncer connection pooler.The value must be a valid JSON object; invalid JSON raises a configuration error.Backend Access Control
Backend Access Control
Enable per-user dataset isolation for multi-tenant scenarios.This feature is available for both SQLite and Postgres.
Troubleshooting
Common Issues
Common Issues
Postgres Connectivity: Verify the database is listening on Docker Networking: Use
DB_HOST:DB_PORT and credentials are correct:host.docker.internal for host-to-container access on macOS/Windows.SQLite Concurrency: SQLite connections now open in WAL (Write-Ahead Logging) journal mode with synchronous=NORMAL and a 120-second busy timeout, and the driver connect timeout is also 120 seconds. This lets concurrent writers wait for the write lock (up to the busy timeout) instead of immediately failing, which greatly reduces the sqlite3.OperationalError: database is locked errors that could occur under Cognee’s parallel cognify() writes. No configuration is required — these settings apply automatically to every SQLite connection. WAL mode creates -wal and -shm sidecar files next to the database file; include them when backing up or copying the database. For heavy multi-user or multi-process workloads, still prefer Postgres.SQLite File Locks on Windows (pruning/deleting): When pruning or deleting a SQLite database, Cognee now disposes the cached SQLAlchemy engine (clearing the relational-engine cache and forcing garbage collection) before removing the file, so the underlying connection releases the file handle. If a stubborn Windows file lock still prevents removal after the retries, deletion no longer raises — it logs a warning and continues. In that case, the SQLite file may remain on disk and can be removed manually after the process releases the handle.Neon SSL and connect args
Neon SSL and connect args
Neon requires SSL/TLS. If you use a full Neon connection string, keep If you use split
sslmode=require in the URL:DB_* settings instead of DATABASE_URL, pass SSL through DATABASE_CONNECT_ARGS:DATABASE_CONNECT_ARGS must be valid JSON. Invalid JSON raises a configuration error before Cognee connects.Missing LLM API key
Missing LLM API key
Operations that extract or answer over memory need an LLM provider. If See LLM Providers for provider-specific settings.
remember(), cognify(), recall(), or related workflows fail because no LLM credentials are configured, set the provider API key in your environment:asyncpg prepared-statement / connection-pooler errors
asyncpg prepared-statement / connection-pooler errors
On Postgres and PGVector, Cognee connects through the asyncpg driver, which caches prepared statements per connection. When you place a transaction-mode connection pooler in front of Postgres — PgBouncer in or as intermittent These connect args are forwarded to the main relational engine, the per-dataset PGVector engines, and the
transaction mode, or the Supabase / Neon connection poolers — a single client connection is multiplexed across many short-lived server backends. The cached statement names can then collide or vanish between checkouts, surfacing as:connection is closed / InterfaceError pool errors under concurrency.Preferred fix — use the direct (session-mode) endpoint. Point DB_HOST (and VECTOR_DB_HOST) at the direct Postgres endpoint rather than the transaction pooler. Cognee already does this for its own CREATE/DROP DATABASE maintenance work, rewriting a Neon -pooler. host to the direct endpoint, because those statements cannot run through PgBouncer.If you must route through a transaction-mode pooler, disable asyncpg’s statement cache through DATABASE_CONNECT_ARGS:GRAPH_DATABASE_PROVIDER="postgres" graph engine, so all three asyncpg connections stop caching prepared statements. You can combine them with the SSL keys in the same JSON object (for example {"ssl": "require", "statement_cache_size": 0}).Too many connections (Neon free tier / hosted Postgres limits)
Too many connections (Neon free tier / hosted Postgres limits)
When the same Postgres backs relational metadata, PGVector, and the Cognee opens a separate SQLAlchemy connection pool per engine, and the To minimize idle connections entirely, disable pooling so each operation opens and closes its own connection:Alternatively, route application traffic through Neon’s pooled (
GRAPH_DATABASE_PROVIDER="postgres" graph store, Cognee can open more connections than a low connection limit allows — most commonly on Neon’s free tier — surfacing as:DB_* / DATABASE_CONNECT_ARGS settings are reused across all of them:- Relational engine — QueuePool with
pool_size=5andmax_overflow=35(up to 40 connections), pluspool_pre_ping=Trueandpool_recycle=280. - PGVector — when backend access control is off and the relational provider is Postgres, PGVector reuses the relational engine and adds no connections of its own. It creates its own pool only under
ENABLE_BACKEND_ACCESS_CONTROL="true"(one engine per dataset,pool_size=2,max_overflow=20). - Postgres graph store — always its own pool, with leaner defaults
pool_size=2andmax_overflow=20(up to 22 connections). Under access control it is also created per dataset.
GRAPH_DATABASE_PROVIDER="postgres" can reach roughly 40 + 22 connections at peak, and backend access control multiplies the per-dataset pools by the number of datasets.Shrink the pools to fit the server’s max_connections. POOL_ARGS applies to the relational engine and is reused by the Postgres graph engine; VECTOR_POOL_ARGS applies to per-dataset PGVector engines. Both take a JSON object:-pooler) endpoint, which supports far more concurrent clients — but disable asyncpg’s prepared-statement cache when doing so (see the asyncpg prepared-statement / connection-pooler errors accordion above), and keep setup and migrations on the direct endpoint.DatabaseNotCreatedError (Postgres)
DatabaseNotCreatedError (Postgres)
For Postgres, the database named in (The built-in Docker Postgres service from
DB_NAME must already exist before Cognee connects. Unlike SQLite, Cognee does not issue CREATE DATABASE for Postgres — it connects directly to DB_NAME and creates only the tables. If the database itself is missing, create it once with your Postgres tooling:docker compose --profile postgres up -d already creates this database for you.)If you specifically see DatabaseNotCreatedError (“The database has not been created yet. Please call await setup() first.”), Cognee reached Postgres but its tables (e.g. principals) don’t exist yet. Run setup once to initialize the schema:remember() creates the tables automatically through its underlying add() and cognify() steps, so this typically only surfaces when calling search() or recall() first on a fresh database.When to Use Each
- SQLite: Local development, single-user applications, simple deployments
- Postgres: Production environments, multi-user applications, external hosting, co-location with pgvector
- Turso (libSQL): A SQLite drop-in when you want a hosted, replicated database — the same aiosqlite driver and Alembic migrations apply unchanged, with optional embedded-replica sync against a remote Turso primary
Vector Stores
Configure vector databases for embedding storage
Graph Stores
Set up graph databases for knowledge graphs
Overview
Return to setup configuration overview