forgedb migrate
Record, build, and run schema migrations that rewrite data-at-rest, and carry a data dir across an engine generation.
Schema evolution follows the generate-then-compile model: edit schema.forge, regenerate,
rebuild. Additive changes (a new model, a new nullable field) survive automatically on
reopen. Everything else rewrites data-at-rest, and forgedb migrate drives that through a
generated offline transformer. The migrations feature guide
has the full workflow.
Every subcommand requires --schema, and none of them discovers anything. The schema
names the app: migrations/ is read beside it, and the build cache is keyed by it.
Nothing is inferred from your working directory.
Subcommands#
| Command | Purpose |
|---|---|
create <description> | Diff the schema against the recorded snapshot, record + classify the change, and ask about anything it cannot prove. |
status | Report an app's lineage. |
build --from F --to T | Generate + compile the offline transformer for a version range. |
run --from F --to T --src S --dest D | Run a built transformer over a source → destination data directory. |
engine --src S --dest D | Carry a data dir across a ForgeDB byte-format generation. |
create#
forgedb migrate create <description> --schema <PATH> [--no-auto]| Flag | Type / default | Meaning |
|---|---|---|
<description> | string (required) | Human description of the migration. |
-s, --schema <PATH> | path (required) | The app this migration belongs to. migrations/ is read beside it. |
--no-auto | bool (false) | Opt out of the interactive prompt, not of detection. The diff is identical either way; what this decides is whether a change ForgeDB cannot prove a value for stops the run with a hard error naming it, or asks you a question. A session with no terminal behaves as if this were passed. |
Detection is what create does, so there is no flag for it — --auto was removed in 0.5.0 and
errors, naming --no-auto. There is also no way to create a migration ForgeDB did not detect: a
record's changes array is derived from a schema diff, so it cannot disagree with
migrations/schemas/vN.forge.
A change ForgeDB can prove needs no input: a nullable add, a drop, a value-preserving
widening, or an add whose field carries a resolvable @default. Anything else is asked about at
create time — a constant, a copy of another field, or "I'll write the transform" — and your
answer is recorded as data in the migration record, which migrate build then lowers into the
generated transformer.
status#
forgedb migrate status --schema <PATH>build#
forgedb migrate build --schema <PATH> --from <F> --to <T>| Flag | Type / default | Meaning |
|---|---|---|
-s, --schema <PATH> | path (required) | The app to build the transformer for. |
--from <F> | u32 (required) | Origin (current on-disk) format version. |
--to <T> | u32 (required) | Destination format version. |
The transformer is emitted into the app's build-cache container as
transform-<from>-<to>/ and compiled as a member of the project's cargo workspace. The
command prints the binary's path — the one cargo reported, existence-checked.
--schema selects the app, and nothing else
The transformer is generated from the committed per-version schemas under the app's
migrations/, so a drifted current schema cannot change a historical hop.
run#
forgedb migrate run --schema <PATH> --from <F> --to <T> --src <DATA> --dest <MIGRATED>| Flag | Type / default | Meaning |
|---|---|---|
-s, --schema <PATH> | path (required) | The app whose transformer to run. |
--from <F> / --to <T> | u32 (required) | The range. Together with --schema these name the exact cache member build produced. |
--src <DATA> | path (required) | Source data directory at the origin format version. |
--dest <MIGRATED> | path (required) | Destination directory to materialize (must be absent/empty). |
run compiles nothing. If the binary is missing it hard-errors naming the cache path and
tells you to run migrate build — there is no fallback that quietly rebuilds somewhere
else.
engine#
forgedb migrate engine --schema <PATH> --src <DATA> --dest <MIGRATED>| Flag | Type / default | Meaning |
|---|---|---|
-s, --schema <PATH> | path (required) | The app. The same schema is baked on both sides of the hop. |
--src <DATA> | path (required) | Source data directory at the old engine generation. |
--dest <MIGRATED> | path (required) | Destination directory to materialize (must be absent/empty). |
Orthogonal to the schema-version transformer, and it needs its own command for that
reason: an engine bump changes no .forge, so it produces no lineage hop and
build/run would replay nothing. Versions are read from the data directory's own
manifests; migrating backwards is refused and tells you to upgrade the CLI instead.
Removed: `migrate up`, `-o/--output`, `--bin-dir`
migrate up was a wrapper over build + run; run the two commands. -o/--output
(on build and engine) and --bin-dir (on run) chose where the transformer was
built — ForgeDB owns that now, and it is a member of the project's cache workspace
rather than a [package] dropped under whatever cargo root you were standing in. All
three still parse, and all three error naming their replacement. The per-tenant sweep
and --from auto-detection that left with up are tracked for restoration as #373.
Examples#
Record an additive change and regenerate:
forgedb migrate create "add note field" --schema schema.forge
forgedb generateBuild a transformer and run it over one data directory:
forgedb migrate build --schema schema.forge --from 1 --to 2
forgedb migrate run --schema schema.forge --from 1 --to 2 \
--src ./data --dest ./data-migratedCarry a data dir across an engine generation:
forgedb migrate engine --schema schema.forge --src ./data --dest ./data-v2