Migrate is a SQLite-first migration toolchain built around F# schema scripts (.fsx).
It provides both a hot-migration workflow (migrate -> drain -> cutover) and a one-shot offline workflow (offline), plus type-safe code generation from reflected schema types.
If you just want to test the tool without installing .Net, then you can use a Docker image:
podman run -it 'mcr.microsoft.com/dotnet/sdk:10.0' bashInside the container run:
export PATH="$PATH:/root/.dotnet/tools"After having .Net in your system you can run
dotnet tool install --global migtoolBuild, pack, and install the current branch as a global mig tool from the local package output:
dotnet fsi build.fsxRun specific FAKE targets when needed:
dotnet fsi build.fsx -- --target Build
dotnet fsi build.fsx -- --target PackToolRun the installed local tool directly:
mig --helpAssuming:
- an existing SQLite database named
<dir>-<old-hash>.sqlite - a target schema script at
schema.fsx
# from your project directory:
# - expects ./schema.fsx
# - expects exactly one source db matching <dir>-<old-hash>.sqlite
# - derives target db as <dir>-<schema-hash>.sqlite
mig plan
mig migrate
# then continue in the same directory (paths auto-resolve)
mig status
mig drain
mig cutover
# optional, after traffic has fully moved to the new service:
mig archive-old
# from a different directory:
mig migrate -d /path/to/project
# if migrate fails and you need to clear failed migration artifacts:
mig reset --dry-run
mig resetWhen you want to bootstrap a database directly from schema.fsx (no source DB yet):
# from your project directory:
# - expects ./schema.fsx
# - derives db path as <dir>-<schema-hash>.sqlite
mig initWhen downtime is acceptable and you want to create the fully migrated target DB in one command:
# from your project directory:
# - expects ./schema.fsx
# - expects exactly one source db matching <dir>-<old-hash>.sqlite
# - derives target db as <dir>-<schema-hash>.sqlite
# - archives the old db into ./archive/ after the copy succeeds
mig offline- F# schema reflection from
.fsxscripts - FK-aware bulk copy and replay with ID mapping
- Replay checkpoints and drain safety validation
- Schema identity metadata (
schema_hash, optionalschema_commit) persisted in new database - Operational status reporting for old/new database migration state
- Optional old-database archival into
archive/after cutover - Transactional ASP.NET Core request composition via
MigLib.WebandwebResult
specs/database_dsl.mdspecs/hot_migrations.mdspecs/mig_command.mdspecs/operator_runbook.mdspecs/web_result.md
mig init [--dir|-d <path>]- Create a schema-matched database fromschema.fsxand apply seed inserts (no source DB required).mig codegen [--dir|-d <path>] [--module|-m <name>] [--output|-o <file>]- Generate F# query helpers fromschema.fsxinto a file in the same directory as the schema, emit aDbFileliteral for the schema-bound SQLite filename, and emit a sibling CPM-style.fsproj.mig offline [--dir|-d <path>]- Create the fully migrated target DB in one step, then archive the old DB intoarchive/.mig migrate [--dir|-d <path>]- Create the new DB from schema, copy data, and start recording on old DB.mig plan [--dir|-d <path>]- Print dry-run inferred paths, schema diff summary, and replay prerequisites without mutating DBs.mig drain [--dir|-d <path>]- Switch old DB to draining mode and replay pending migration log entries.mig cutover [--dir|-d <path>]- Verify drain completion plus old marker/log replay safety, switch new DB toready, and remove replay-only tables.mig archive-old [--dir|-d <path>]- Optional archival of the old DB intoarchive/, replacing any existing archive with the same name.mig reset [--dir|-d <path>] [--dry-run]- Reset failed/aborted migration artifacts, or inspect reset impact without mutating DB files.mig status [--dir|-d <path>]- Show marker/status state and migration counters for operational visibility.
How to contribute:
- Open an issue to discuss the change and approach
- Add relevant tests
- Create a pull request mentioning the issue and also including a summary of the problem and approach to solve it
- Wait for the review
This project wouldn't have been possible without the amazing open-source community. We're especially grateful to:
- Fabulous.AST - An elegant F# DSL for code generation that made creating and manipulating F# AST a joy
- Fantomas - The excellent F# code formatter that ensures our generated code is beautiful and consistent
If you find these projects valuable, please consider supporting them:
- Star their repositories
- Contribute to their projects
- Donate to support their continued development
