How to Run Database Migrations and Check the Current Version in Open Notebook
Use the synchronous MigrationManager class from open_notebook/database/migrate.py to manually execute SurrealDB schema migrations or query the current database version without launching the full API server.
Open Notebook stores its data in SurrealDB and manages schema evolution through numbered SurrealQL migration files. While the API service automatically applies pending migrations on startup, you can also run database migrations manually using the synchronous wrapper exposed in the backend codebase. This approach is essential for CI/CD pipelines, local debugging, or maintenance scripts where you require explicit control over the database state.
Migration Architecture and Key Files
The migration system in lfnovo/open-notebook uses a dual-layer architecture that separates the asynchronous execution engine from a synchronous public interface.
The implementation is split across three critical locations:
open_notebook/database/migrate.py– A thin synchronous façade that exposes theMigrationManagerclass for direct use in scripts and REPLs.open_notebook/database/async_migrate.py– The core asynchronous migration engine that reads and executes SurrealQL files.open_notebook/database/migrations/– The directory containing ordered migration files (e.g.,1.surrealql,2.surrealql) that define schema changes.
When you instantiate MigrationManager, it handles the asyncio event loop internally, allowing you to call migration methods from standard synchronous Python code without managing async/await syntax.
How to Check the Current Migration Version
To determine which migration version the database is currently running, use the get_current_version() method. This queries the internal _sbl_migrations table in SurrealDB and returns an integer representing the applied version, or 0 if the migrations table does not yet exist.
from open_notebook.database.migrate import MigrationManager
manager = MigrationManager()
current = manager.get_current_version()
print(f"The database is at migration version {current}")
The _sbl_migrations table stores each applied migration as a record containing the version number and an applied_at timestamp, enabling the manager to determine exactly which schema changes are present.
How to Run Database Migrations Manually
The MigrationManager exposes three primary methods for manual control:
get_current_version()– Returns the integer version stored in_sbl_migrations.needs_migration– A boolean property that returnsTruewhen the database version is lower than the latest migration file available in the migrations directory.run_migration_up()– Executes every pending "up" migration in sequential order, updating the version record after each successful application.
Because this wrapper is synchronous, you can invoke these methods from any Python context without worrying about event loops or coroutine management.
Script-Based Migration Execution
Create a standalone script to apply pending migrations during deployment or setup:
# scripts/run_migrations.py
from open_notebook.database.migrate import MigrationManager
def main() -> None:
manager = MigrationManager()
if manager.needs_migration:
print("Applying pending migrations...")
manager.run_migration_up()
print("Migrations applied successfully.")
else:
print("Database is already up-to-date.")
if __name__ == "__main__":
main()
Execute the script after ensuring your SurrealDB instance is accessible:
python scripts/run_migrations.py
Verifying Migration Status Before Execution
For idempotent deployment logic, check the status before deciding whether to migrate:
from open_notebook.database.migrate import MigrationManager
manager = MigrationManager()
if manager.needs_migration:
print(f"Current version: {manager.get_current_version()}")
manager.run_migration_up()
print(f"Updated to version: {manager.get_current_version()}")
else:
print("No migrations required.")
Interactive REPL Workflow
You can inspect and manipulate migrations directly in an interactive Python session:
>>> from open_notebook.database.migrate import MigrationManager
>>> mm = MigrationManager()
>>> mm.get_current_version()
3
>>> mm.needs_migration
True
>>> mm.run_migration_up()
Integrating Migrations into CI/CD Pipelines
Use the manager in shell scripts or CI workflows to ensure database consistency before running tests or deployments. This example exits with code 1 if migrations are pending, failing the pipeline step:
python -c "from open_notebook.database.migrate import MigrationManager; \
m = MigrationManager(); \
import sys; \
sys.exit(0 if not m.needs_migration else 1)"
Alternatively, automatically apply migrations and verify success:
python -c "from open_notebook.database.migrate import MigrationManager; \
m = MigrationManager(); \
m.run_migration_up() if m.needs_migration else None; \
print(f'Database at version {m.get_current_version()}')"
Where Migration State is Stored
Open Notebook tracks migration state in a special SurrealDB record type called _sbl_migrations. Each time run_migration_up() applies a migration file, it inserts a record containing:
version: The integer version number of the applied migration (starting at 1).applied_at: A timestamp marking when the migration was executed.
The MigrationManager queries this table to calculate needs_migration and to determine the starting point for run_migration_up(). If this table is missing or empty, the manager treats the database as being at version 0.
Summary
- Automatic execution: Migrations run automatically when the FastAPI server starts, but manual execution is available via
MigrationManager. - Synchronous interface: The
open_notebook/database/migrate.pymodule provides a blocking API that wraps the async engine, making it suitable for scripts and REPLs. - Version tracking: Query
get_current_version()to read the current schema version from the_sbl_migrationstable. - Pending detection: Use the
needs_migrationproperty to check if the database lags behind the latest migration files. - Manual execution: Call
run_migration_up()to apply all pending SurrealQL migrations in order. - No server required: All migration operations work with only a SurrealDB connection, without requiring the full application server to run.
Frequently Asked Questions
Can I run database migrations without starting the Open Notebook API server?
Yes. The MigrationManager only requires a valid SurrealDB connection using the same configuration as the API. You can execute migrations from standalone scripts, Python REPLs, or CI environments without launching the FastAPI application.
How does Open Notebook track which migrations have already been applied?
The system stores migration metadata in a SurrealDB table named _sbl_migrations. Each record contains the migration version number and an applied_at timestamp. The get_current_version() method queries this table to determine the current schema state.
What file format are the migrations written in?
Migration files are written in SurrealQL, the query language for SurrealDB. They are stored as numbered files (e.g., 1.surrealql, 2.surrealql) in the open_notebook/database/migrations/ directory and executed sequentially by the migration engine.
How can I check if my database needs migrations before deploying?
Use the needs_migration boolean property on a MigrationManager instance. If it returns True, the database version is lower than the latest available migration file, and you should call run_migration_up() to bring the schema up to date.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →