Skip to main content
Khora ships its schema as Alembic migrations bundled inside the package at khora/db/migrations/. This applies to PostgreSQL-backed deployments. The embedded sqlite_lance stack runs the portable subset of the same migration chain.

Who runs migrations?

The schema must exist before you call Khora(). Two options:

Let Khora run them

async with Khora(run_migrations=True) as kb:
    ...
Khora takes a PostgreSQL advisory lock (60s timeout), applies any pending migrations, and releases it. Safe under concurrent startup: one process migrates, the others wait and no-op. Good for single-process apps and tests.

Run them out-of-band

Pre-deploy with the Alembic CLI. The migration directory resolves via script_location = khora:db/migrations when Khora is installed as a dependency:
uv run alembic upgrade head

The version table

Khora’s migrations live in khora_alembic_version, not the default alembic_version. This means Khora’s history never collides with your own application’s Alembic migrations. Point your app at alembic_version and leave Khora’s table untouched.

Skip-ahead and fresh databases

  • Fresh database: run_migrations() detects the absence of khora_alembic_version (via information_schema) and creates every table from scratch.
  • Skip-ahead: if the database is at a revision newer than the installed Khora package (another service already migrated it), Khora skips gracefully and returns MigrationResult(success=True, skipped=True, ...).
Skip-ahead is a safety net, not a coordination tool: don’t pin different services to different Khora major versions against a shared PostgreSQL database. Run the same major across services.

Dialect-conditional migrations

A few migrations use PostgreSQL-only features (BRIN/GIN indexes, CREATE INDEX CONCURRENTLY, partial indexes over bi-temporal columns) that have no SQLite analogue. Those scripts gate on dialect.name == "postgresql" and skip silently on sqlite_lance, so the embedded stack runs the same chain without errors. Portable column additions run on both dialects. You don’t manage this. It’s automatic.

Migrating from the removed graphrag engine

The graphrag engine was removed; vectorcypher is the drop-in replacement. Pass engine_kwargs={"skeleton_core_ratio": 1.0} for graphrag-equivalent full extraction, or accept VectorCypher’s default selective extraction (cheaper). Existing graphrag-ingested data stays queryable via vectorcypher against the same database. The table shapes are identical. See VectorCypher.
Per-release migration details (which revision added which column/index) live in the khora repo’s CHANGELOG.md, not here. This page is the stable operational contract.
database

Storage backends

The PostgreSQL + Neo4j stack the migrations target, and the embedded alternative.
rocket_launch

Quickstart

Bring up the databases and run your first migration.