> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cognee.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Turso Local

> Run every cognee store — relational, graph, vector, and session cache — on local Turso database files

A minimal guide to running cognee entirely on Turso, the Rust rewrite of SQLite. Every layer — relational metadata, the knowledge graph, the embeddings, and the session cache — lives in a local database file, so you get a full cognee stack with no database server, and the script's three phases show the data surviving a process restart.

## Before You Start

* Complete [Quickstart](/getting-started/quickstart) to understand basic operations
* Ensure you have [LLM Providers](/setup-configuration/llm-providers) configured (`LLM_API_KEY`)
* Install the Turso extra: `pip install "cognee[turso]"`
* Optionally set `TURSO_EXAMPLE_ROOT` to choose where the database files go; by default they land in `.turso_example` next to the script. The script forces `DB_PROVIDER`, `GRAPH_DATABASE_PROVIDER`, `VECTOR_DB_PROVIDER`, and `CACHE_BACKEND` to `turso` itself, so no `.env` changes are needed
* Read [Graph Stores](/setup-configuration/graph-stores), [Vector Stores](/setup-configuration/vector-stores), and [Relational Databases](/setup-configuration/relational-databases) for the per-store settings

<Warning>
  Unset `SYSTEM_ROOT_DIRECTORY` and `DATA_ROOT_DIRECTORY` in your `.env` before running the script. Cognee loads `.env` with override when it is imported, so if `.env` sets them, the Turso files land in those directories instead, and `cleanup` deletes every dataset stored there.
</Warning>

## Code in Action

Run the script three times, once per phase:

```bash theme={null}
python turso_local_example.py ingest   # add + cognify + search
python turso_local_example.py verify   # new process: search only
python turso_local_example.py cleanup  # forget everything + remove files
```

```python theme={null}
import asyncio
import os
import pathlib
import shutil
import sys

ROOT = pathlib.Path(
    os.environ.get("TURSO_EXAMPLE_ROOT", pathlib.Path(__file__).parent / ".turso_example")
)

# The storage roots must be known before cognee is imported (its logging reads them).
os.environ.setdefault("DATA_ROOT_DIRECTORY", str(ROOT / "data"))
os.environ.setdefault("SYSTEM_ROOT_DIRECTORY", str(ROOT / "system"))

import cognee  # noqa: E402
from cognee import SearchType  # noqa: E402
from cognee.shared.logging_utils import ERROR, setup_logging  # noqa: E402

# Importing cognee loads .env with override=True, so the providers are forced here,
# after the import: this example is about running every layer on Turso, whatever the
# .env says. The database configs are read lazily, on first use.
for variable in ("DB_PROVIDER", "GRAPH_DATABASE_PROVIDER", "VECTOR_DB_PROVIDER", "CACHE_BACKEND"):
    os.environ[variable] = "turso"
for variable in ("DB_TURSO_URL", "DB_TURSO_AUTH_TOKEN", "GRAPH_DATABASE_KEY", "VECTOR_DB_URL"):
    os.environ.pop(variable, None)  # remote settings are rejected; use local files

# The cache config is already built during cognee's import; drop the cached
# instances so every settings class re-reads the environment set above.
from cognee.infrastructure.databases.cache.config import get_cache_config  # noqa: E402
from cognee.infrastructure.databases.graph.config import get_graph_config  # noqa: E402
from cognee.infrastructure.databases.relational.config import get_relational_config  # noqa: E402
from cognee.infrastructure.databases.vector.config import get_vectordb_config  # noqa: E402

for cached_config in (
    get_cache_config,
    get_graph_config,
    get_relational_config,
    get_vectordb_config,
):
    cached_config.cache_clear()

DATASET = "turso_example"
TEXT = """
Turso is a rewrite of SQLite in Rust. It keeps the SQLite file format and SQL dialect,
adds multi-version concurrency control so several writers can commit at the same time,
and ships vector distance functions for similarity search. cognee stores its relational
metadata, its knowledge graph and its embeddings in Turso database files.
"""
QUESTION = "What does Turso add on top of SQLite?"


async def show_engines() -> None:
    """Print the engine each layer runs on; ``turso_version()`` exists only on the rewrite."""
    from sqlalchemy import text

    from cognee.infrastructure.databases.graph import get_graph_engine
    from cognee.infrastructure.databases.relational import get_relational_engine
    from cognee.infrastructure.databases.vector import get_vector_engine_async

    relational = get_relational_engine()
    async with relational.engine.connect() as connection:
        version = (await connection.execute(text("SELECT turso_version()"))).scalar()
        journal = (await connection.execute(text("PRAGMA journal_mode"))).scalar()
    print(f"relational: {type(relational).__name__} on Turso {version} (journal_mode={journal})")
    print(f"graph:      {type(await get_graph_engine()).__name__}")
    print(f"vector:     {type(await get_vector_engine_async()).__name__}")
    from cognee.infrastructure.databases.cache import get_cache_engine

    cache = get_cache_engine()
    print(f"cache:      {type(cache).__name__} on {cache.db_uri.split('://')[0]}")


async def search() -> None:
    results = await cognee.search(
        query_text=QUESTION, query_type=SearchType.GRAPH_COMPLETION, datasets=[DATASET]
    )
    print(f"\nQ: {QUESTION}")
    for result in results:
        print(f"A: {result}")
    chunks = await cognee.search(
        query_text="concurrency control", query_type=SearchType.CHUNKS, datasets=[DATASET]
    )
    print(f"\n{len(chunks)} chunk(s) matched a vector search for 'concurrency control'.")


async def ingest() -> None:
    # add() creates the relational database (and its directory) on first use, so the
    # engines are inspected after it, exactly as any cognee flow would see them.
    await cognee.add(TEXT, dataset_name=DATASET)
    await show_engines()
    await cognee.cognify(datasets=[DATASET])
    print("\nadd + cognify done; graph, vectors and metadata are in", ROOT)
    await search()


async def verify() -> None:
    """Runs in a fresh process: nothing is ingested, the stored files must answer."""
    await show_engines()
    await search()


async def cleanup() -> None:
    await cognee.forget(everything=True)
    await cognee.wait_for_background_tasks()
    print("forgot everything")


def main() -> None:
    setup_logging(ERROR)
    phase = sys.argv[1] if len(sys.argv) > 1 else "ingest"
    if phase == "cleanup":
        asyncio.run(cleanup())
        shutil.rmtree(ROOT, ignore_errors=True)
        print("removed", ROOT)
        return
    asyncio.run({"ingest": ingest, "verify": verify}[phase]())


if __name__ == "__main__":
    main()
```

## What Just Happened

### Step 1: Choose Where the Files Live

```python theme={null}
ROOT = pathlib.Path(
    os.environ.get("TURSO_EXAMPLE_ROOT", pathlib.Path(__file__).parent / ".turso_example")
)

# The storage roots must be known before cognee is imported (its logging reads them).
os.environ.setdefault("DATA_ROOT_DIRECTORY", str(ROOT / "data"))
os.environ.setdefault("SYSTEM_ROOT_DIRECTORY", str(ROOT / "system"))
```

In this script every Turso database is a file under the system root directory, so pointing both roots at one folder keeps this example's data in a single place you can inspect or delete. They are set before `import cognee` because cognee reads them at import time.

### Step 2: Force Every Layer onto Turso

```python theme={null}
for variable in ("DB_PROVIDER", "GRAPH_DATABASE_PROVIDER", "VECTOR_DB_PROVIDER", "CACHE_BACKEND"):
    os.environ[variable] = "turso"
for variable in ("DB_TURSO_URL", "DB_TURSO_AUTH_TOKEN", "GRAPH_DATABASE_KEY", "VECTOR_DB_URL"):
    os.environ.pop(variable, None)  # remote settings are rejected; use local files

# The cache config is already built during cognee's import; drop the cached
# instances so every settings class re-reads the environment set above.
from cognee.infrastructure.databases.cache.config import get_cache_config  # noqa: E402
from cognee.infrastructure.databases.graph.config import get_graph_config  # noqa: E402
from cognee.infrastructure.databases.relational.config import get_relational_config  # noqa: E402
from cognee.infrastructure.databases.vector.config import get_vectordb_config  # noqa: E402

for cached_config in (
    get_cache_config,
    get_graph_config,
    get_relational_config,
    get_vectordb_config,
):
    cached_config.cache_clear()
```

Importing cognee loads `.env` with override, so the providers are set after the import, whatever `.env` says. Remote connection settings are removed so every store uses a local file, and clearing the cached config objects makes each settings class re-read the environment on first use.

### Step 3: Ingest and Inspect the Engines

```python theme={null}
async def ingest() -> None:
    # add() creates the relational database (and its directory) on first use, so the
    # engines are inspected after it, exactly as any cognee flow would see them.
    await cognee.add(TEXT, dataset_name=DATASET)
    await show_engines()
    await cognee.cognify(datasets=[DATASET])
    print("\nadd + cognify done; graph, vectors and metadata are in", ROOT)
    await search()
```

`add()` creates the relational database, then `show_engines()` prints the adapter behind each layer — querying `turso_version()`, which exists only on the Turso rewrite, proves the relational store really runs on it. `cognify()` builds the graph and embeddings, and `search()` runs a `GRAPH_COMPLETION` query against the graph and a `CHUNKS` query against the vector store.

### Step 4: Verify Persistence and Clean Up

```python theme={null}
async def verify() -> None:
    """Runs in a fresh process: nothing is ingested, the stored files must answer."""
    await show_engines()
    await search()


async def cleanup() -> None:
    await cognee.forget(everything=True)
    await cognee.wait_for_background_tasks()
    print("forgot everything")
```

The `verify` phase runs in a new process and ingests nothing, so its answers can only come from the Turso files written by `ingest`. `cleanup` forgets all data, and `main()` then removes the example root directory.

## Advanced Usage

<Accordion title="Concurrent Writes with MVCC">
  Set `TURSO_JOURNAL_MODE=mvcc` to run the graph and vector stores on Turso's concurrent writes (multi-version concurrency control). The relational database and the session cache always stay on `wal`. The mode is experimental upstream: each database file gains a `-log` companion and can no longer be opened by stock SQLite.
</Accordion>

<Columns cols={3}>
  <Card title="Graph Stores" icon="network" href="/setup-configuration/graph-stores">
    Every graph backend cognee supports, and their settings.
  </Card>

  <Card title="Vector Stores" icon="database" href="/setup-configuration/vector-stores">
    Per-provider vector settings, including the Turso block.
  </Card>

  <Card title="Store Configurations" icon="sliders-horizontal" href="/guides/store-configurations#turso">
    The same Turso stack as a copy-paste `.env` block.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.