Skip to content

Migrations

Schemas evolve. Bowerbird provides tools to migrate your notes when your schema changes, keeping your vault consistent without manual edits.

When you modify your schema, existing notes may become inconsistent:

  • Remove a select option — Notes may reference invalid values
  • Rename a type — Notes live in the wrong directory
  • Remove a field — Old notes have orphaned data

Migrations update existing notes to match the new schema.

Bowerbird’s migration system follows four principles:

  1. Migrations are explicit — You intentionally trigger migrations; they don’t run automatically
  2. Safe by default — Dry-run mode shows what would change before applying
  3. Backup by default — A backup is created before changes are applied
  4. Git handles history — Bowerbird tracks current and last-applied states; use Git for deeper history

The typical workflow has four steps:

Edit .bwrb/schema.json to make your changes (add fields, rename types, etc.).

Run bwrb schema diff to see pending changes:

Terminal window
bwrb schema diff
Pending Schema Changes
Deterministic changes (will be auto-applied):
+ Add field "importance" to type "idea"
+ Add field "source" to type "idea"
Non-deterministic changes (require confirmation):
- Remove field "priority" from type "idea"
Note: Schema version is still 1.0.0.
You'll be prompted to update it when running `bwrb schema migrate --execute`.
Run `bwrb schema migrate` to preview the migration.
Run `bwrb schema migrate --execute` to apply changes.

Run bwrb schema migrate (without --execute) to see what would happen:

Terminal window
bwrb schema migrate
Migration Preview (Dry-Run)
Deterministic changes (will be auto-applied):
+ Add field "importance" to type "idea"
+ Add field "source" to type "idea"
Non-deterministic changes (require confirmation):
- Remove field "priority" from type "idea"
Files scanned: 4
Files affected: 0
Run `bwrb schema migrate --execute` to apply these changes.

By default the preview shows schema-level operations plus a scanned/affected file count. To also see the concrete per-note before→after edits, add --show-changes:

Terminal window
bwrb schema migrate --show-changes
Per-note changes:
Ideas/Idea A.md:
importance: (empty) → medium
priority → rank: 3

Missing or null values render as (empty). On large vaults the per-note list is capped (200 lines) with a ... and N more changes footer; the schema-level summary is never truncated. The flag also works with --execute to echo what was applied.

In --output json mode, the per-note changes are always included under data.fileChanges (uncapped), so automation never needs the flag.

Migration discovery follows valid frontmatter types across the vault. A typed note that has been moved outside its configured output directory is still included in totalFiles, change planning, and execution; its separate wrong-directory audit issue does not make it disappear from schema evolution.

If a change would clear a required field and the schema has no default that can replace it safely, preview JSON sets data.blocked: true and lists structured data.blockers with the note path and field. Execute fails closed before any note, backup, schema version, applied snapshot, or migration-history write. Set valid values on the named notes, then rerun the migration. Bowerbird never guesses which remaining select option you intended.

When ready, execute the migration:

Terminal window
bwrb schema migrate --execute

This will:

  1. Prompt for a new schema version
  2. Create a backup (unless --no-backup is passed)
  3. Apply changes to affected notes
  4. Save the new schema snapshot
  5. Record the migration in history

For non-interactive environments such as CI or agent shells, provide the version explicitly:

Terminal window
bwrb schema migrate --execute --set-version 1.1.0 --output json

If the migration includes non-deterministic changes (for example, removing a field that may delete note data), also pass --yes to accept that confirmation:

Terminal window
bwrb schema migrate --execute --set-version 2.0.0 --yes --output json

Some schema edits change the schema’s shape without requiring any note update — adding a select option is the canonical example. In that case --execute reports no affected files but still refreshes the snapshot, so that if the option is later removed, the removal is diffed against the current schema rather than a stale snapshot that never had the option (which would silently miss the now-invalid values).

Bowerbird classifies schema changes into two categories:

These can be applied automatically without user input:

ChangeNotes Don’t Need Updates Because…
Add fieldMissing fields are valid (fields aren’t required by default)
Add select optionExisting values remain valid
Allow multiple values (multiple false → true)An existing scalar is wrapped into a single-element array — no data is lost
Add typeNo existing notes to update

These require confirmation because they affect existing data:

ChangeWhat Happens
Remove fieldField is removed from affected notes
Remove some select options (field stays a constrained select)Note values no longer in the remaining allowed set are dropped — a scalar becomes empty, an array is filtered to its still-valid members (clear-invalid-options)
Remove all select options (field becomes free text / unconstrained)The field no longer constrains values, so every existing value is valid and kept — the change is flagged for review, not cleared (review-field)
Make field requiredNotes missing a value are flagged for review; bwrb cannot fabricate a value (review-field)
Disallow multiple values (multiple true → false)Notes holding arrays are flagged for review; collapsing an array is lossy, so bwrb does not auto-change them (review-field)
Change relation sourceExisting links may now point at the wrong type and are flagged for review (review-field)
Rename typeNotes are moved to the new directory
Remove typeExisting notes become orphaned (warning)

When you run bwrb schema migrate --execute, Bowerbird suggests a version bump based on your changes:

Change SeverityVersion BumpExample
Breaking (removals, renames)Major1.0.0 → 2.0.0
AdditionsMinor1.0.0 → 1.1.0
No structural changesPatch1.0.0 → 1.0.1

You can accept the suggestion or enter your own version.

In non-interactive mode, use --set-version <x.y.z> instead of the prompt.

Bowerbird stores migration state in .bwrb/:

.bwrb/
├── schema.json # Current schema (you edit this)
├── schema.applied.json # Last successfully migrated schema
├── migrations.json # History of applied migrations
└── backups/ # Timestamped backups before migrations
  • schema.json: Your current schema definition
  • schema.applied.json: Snapshot from the last migration — used to compute diffs
  • migrations.json: Log of all migrations with timestamps and changes
  • backups/: Timestamped directories containing pre-migration file copies

schema.applied.json is migration bookkeeping only. Schema inspection commands (for example bwrb schema list) always read the current schema.json. Pending migrations may be shown as a warning or status line, but the schema output never comes from the snapshot.

See past migrations with:

Terminal window
bwrb schema history
bwrb schema history --limit 5

Bowerbird does not have a rollback command. Instead:

  1. Use Git — Commit your schema and notes together. Roll back with git checkout or git revert
  2. Use backups — Migrations create backups in .bwrb/backups/
  3. Fix forward — Make additional schema changes and run another migration

This design keeps Bowerbird focused on schema management while Git handles version control.

When you first use migrations on a vault:

Terminal window
bwrb schema diff
No previous schema snapshot found.
This is either a new vault or migrations haven't been used yet.
Run `bwrb schema migrate --execute` to create the initial snapshot.

Run the initial migration to establish a baseline:

Terminal window
bwrb schema migrate --execute
Initial schema snapshot created (version 1.0.0)
Future schema changes will be tracked from this point.

Keep schema.json and affected notes in the same commit:

Terminal window
# Make schema changes, then:
bwrb schema migrate --execute
git add .bwrb/ Notes/
git commit -m "Rename priority to importance"

Never run --execute without previewing:

Terminal window
bwrb schema diff # What changed in the schema?
bwrb schema migrate # What will happen to notes?
bwrb schema migrate --execute # Apply when ready

Your schema version communicates intent:

  • Major (2.0.0): Breaking changes that affect how notes are used
  • Minor (1.1.0): New capabilities, backward compatible
  • Patch (1.0.1): Fixes or clarifications

Don’t rely on .bwrb/migrations.json for rollback. It’s for reference, not recovery. Keep your vault in Git.

CommandPurpose
bwrb schema diffShow pending schema changes
bwrb schema migratePreview or apply migrations
bwrb schema historyView migration history