Skip to main content

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.

A focused walkthrough for converting an existing relational database (SQLite or Postgres) into a knowledge graph that can be queried with natural language. Before you start:
  • Complete Quickstart to understand basic operations
  • Ensure you have LLM Providers configured
  • Have connection details for the database you want to migrate

What This Does

Cognee reads your relational database schema (tables, columns, primary keys, foreign keys) and can map it into graph nodes and edges:
  • In full migration mode, each table becomes a TableType node
  • Each row becomes a TableRow node linked to its table
  • Non-key column values can become ColumnValue nodes linked from each row
  • Foreign key relationships become edges between row nodes
  • Migrated nodes and edges are embedded and indexed for semantic search
After migration, you can query your relational data using cognee.recall() with natural language.

1. Configure the Migration Database

Set the source database connection in your .env file:
MIGRATION_DB_PROVIDER="sqlite"
MIGRATION_DB_PATH="/path/to/db/directory"
MIGRATION_DB_NAME="my_database.sqlite"

2. Run the Migration

import asyncio
import os
import tempfile
from pathlib import Path

import cognee
from cognee.api.v1.visualize.visualize import visualize_graph
from cognee.infrastructure.databases.graph import get_graph_engine
from cognee.infrastructure.databases.relational import get_migration_relational_engine
from cognee.infrastructure.databases.relational.config import get_migration_config
from cognee.tasks.ingestion import migrate_relational_database

# Isolate this example from any pre-existing local Cognee state so old SQLite
# metadata files do not interfere with the run.
example_root = Path(tempfile.gettempdir()) / "cognee-relational-migration-example"
os.environ.setdefault("SYSTEM_ROOT_DIRECTORY", str(example_root / "system"))
os.environ.setdefault("DATA_ROOT_DIRECTORY", str(example_root / "data"))
os.environ.setdefault("CACHE_ROOT_DIRECTORY", str(example_root / "cache"))
os.environ.setdefault("ENABLE_BACKEND_ACCESS_CONTROL", "false")

async def main():
    migration_config = get_migration_config()
    migration_config.migration_db_provider = os.environ.get("MIGRATION_DB_PROVIDER", "sqlite")
    migration_config.migration_db_path = os.environ.get("MIGRATION_DB_PATH", "/path/to/db")
    migration_config.migration_db_name = os.environ.get(
        "MIGRATION_DB_NAME", "my_database.sqlite"
    )

    # Start from a clean local state for repeatable runs.
    await cognee.forget(everything=True)

    # Extract the schema from the source database
    engine = get_migration_relational_engine()
    schema = await engine.extract_schema()
    print(f"Loaded schema with {len(schema)} tables: {sorted(schema)}")

    # Migrate schema + all rows into the graph
    graph = await get_graph_engine()
    nodes, edges = await migrate_relational_database(graph, schema=schema)
    print(f"Migrated graph: {len(nodes)} nodes / {len(edges)} edges")

    # Query the migrated data
    results = await cognee.recall(
        query_text="What data does this database contain?",
        top_k=100,
    )
    print("Recall results:")
    print(results)

    # Visualize the migrated graph
    graph_path = Path(__file__).resolve().parent / "relational_migration_graph.html"
    graph_html = await visualize_graph(str(graph_path))
    graph_path.write_text(graph_html, encoding="utf-8")
    print(f"Graph visualization saved at: {graph_path}")

asyncio.run(main())
The migration pipeline itself uses lower-level APIs because it is importing an external relational schema directly into the graph. Once the graph is built, prefer cognee.recall() as the default query interface in v1.0. Set top_k higher (100-200) for broad exploratory queries over large databases, and lower (20-50) for specific lookups to keep LLM context manageable. The example above also isolates Cognee’s local state in a temp directory so repeated runs do not pick up stale metadata from earlier experiments.

Additional information

migrate_relational_database has two modes controlled by the schema_only flag:
ModeFlagWhat is migrated
Full (default)schema_only=FalseTableType, TableRow, optional ColumnValue, and foreign-key edges
Schema onlyschema_only=TrueDatabaseSchema, SchemaTable, and SchemaRelationship datapoints for structural understanding
Schema-only mode does not create TableRow nodes for every record. Instead, it ingests schema-level datapoints and attaches up to a few sample rows as metadata on each SchemaTable node. Use it when you want to explore table structure and relationships without migrating the full dataset:
await migrate_relational_database(graph, schema=schema, schema_only=True)
This is especially useful for large databases when your questions are structural, for example:
  • “What tables exist in this database?”
  • “Which tables are connected by foreign keys?”
  • “What kind of data does the invoices table contain?”
from cognee.api.v1.visualize.visualize import visualize_graph
from pathlib import Path

graph_path = Path("./migration_graph.html")
graph_html = await visualize_graph(str(graph_path))
graph_path.write_text(graph_html, encoding="utf-8")
This generates an HTML file you can open in a browser to explore the graph structure. See Graph Visualization for more options.

Relational Databases

Configure SQLite and Postgres connections

Recall and Search

Learn the current recall flow and lower-level search options

Graph Visualization

Explore your knowledge graph visually