Checking for Updates
Short Version
- With your current
bd, sync remote-backed databases before installing the new binary:bd dolt pushbd dolt pull - Back up with that same current binary, before installing:
bd export --all -o .beads/backup/pre-migrate-$(date +%Y%m%d).jsonl - Upgrade using the command that matches your install method.
- After upgrading:
bd upgrade reviewbd hooks installbd version - If crossing a schema migration on a remote-backed database, only the
designated migrator runs:
bd migrate schemabd dolt push
bd dolt pull with its current binary, then installs the new
one. A clone that already has the new binary adopts the migrated database by
moving its local database aside and running bd bootstrap; bd bootstrap on
its own leaves an existing database untouched. The full procedure is below.
Upgrading
Use the command that matches your install method.Quick install script (macOS/Linux/FreeBSD)
PowerShell installer (Windows)
Homebrew
bd, switch to the
Homebrew core formula:
go install
From Source
After Upgrading
Important: After upgrading, update your hooks:Database Migrations
After major upgrades, check for database migrations:Upgrading to 1.3.0
A 1.2.2 or 1.1.x database sits at schema v53, and 1.3.0 knows v66. That is more than a routine upgrade: 1.2.2 was a recovery release that shipped the 1.1 code under a higher version number, so there is a release line’s worth of schema between the two.Back up first, with the binary you have now
Do this before you install 1.3.0. Under the new binary,bd export triggers
the migration before it exports, so a snapshot taken afterwards is a
post-migration snapshot and cannot protect you against the migration going
wrong. The same ordering rule as the section below applies: do all syncing with
your current binary, since once 1.3.0 is installed the pending-migration
gate refuses bd dolt push and bd dolt pull too.
bd backup takes no backup — it is a command
group that prints help and exits 0:
What the migration looks like
On an embedded or local store, the first command you run after installing applies the whole set, in place. (A shareddolt sql-server is never
auto-migrated — see Shared servers below.) The main series
runs 0054 → 0066 (13 migrations), and then the clone-local series runs through
the same printer with its own numbering, 0012 → 0026 — so it is about
28 migrations, and the counter visibly restarts partway through:
Repair blocked flags after migrating
Migration 0059 can mark issues as blocked when they are not, which drops them out ofbd ready without any error
(#7037). It happens on a
Dolt server older than 2.4.0, and the embedded engine is likely affected too.
Once a database has migrated, run this once for that database on every clone:
"rows_corrected" greater than zero means the database was hit.
It works in embedded, server and proxied-server mode, so run it even where
bd doctor cannot check blocked state.
Upgrade every client that shares a store, together
A bd binary refuses a database migrated past the schema it knows, rather than proceeding blind. One machine upgrading takes the shared store forward and every client still on 1.2.2 stops working. Check for a second binary earlier in yourPATH with which -a bd, and restart any long-running bd serve — noting that
bd --readonly serve is now refused outright, so a server scripted with that
flag will not come back up until you drop it.
If the store is a shared dolt sql-server rather than a local one, follow
Shared servers below: 1.3.0 will not migrate it without
explicit consent, precisely so the fleet upgrade can come first.
If you need to go back, the rollback is a schema-cursor rollback rather than a
downgrade of the data — see
Accidental v1.2.1 Release, whose
procedure is the same for any cursor rollback even though its worked example is
that release.
Once you are on the new binary, bd upgrade review prints exactly the changes
between the version you were running and this one. Several commands changed
defaults, so read it before your first session.
Remote-backed databases and multiple clones
bd refuses to silently apply pending schema migrations to a database that has
a Dolt remote configured. Migrating more than one clone of a shared remote
independently forks the schema, after which bd dolt pull can no longer merge —
the break is silent and, across a primary-key-reshaping migration, unrecoverable
(#4259). The supported flow
is: one machine migrates and publishes; every other clone takes the migrated
database from the remote instead of migrating its own.
This applies to every upgrade that crosses a pending migration on a
remote-backed database — the same procedure whether you are moving to a
prerelease or to a stable release.
The gate is state-aware by default
(#4516): before blocking,
bd consults the remote’s cached schema state and
- auto-migrates when the remote is at the same schema version as this
clone — no one has migrated yet, so this clone is a safe first-mover
(concurrent first-movers converge to identical tables). It reminds you to
bd dolt pushafterwards. This applies to embedded mode only: a shared server always stops for consent, because migrating it changes the schema every connected client sees (see Shared servers below). - stops and directs you to adopt (
bd bootstrap) when the remote has already been migrated by another clone. On a clone that already has a local database,bd bootstrapby itself reportsNothing to do.and changes nothing; adopt with the steps under Multiple clones sharing one remote below. - stops for a human decision when this clone and the remote applied different content for the same migration (a genuine fork), or when the remote’s schema state cannot be read from the cached ref.
BD_SMART_GATE=0 to opt out and make the gate block unconditionally.
The recipes below are the explicit path and work the same in either mode.
Important ordering: once the new binary is installed, a database with
pending migrations is gated on every open — bd dolt push and bd dolt pull are refused too, not just bd migrate. So do all syncing with your
current binary, before you install the new one.
There is one exception, and the gate names it when it applies: if the stop is
the data-behind one — this clone is level with the remote on schema but is
missing commits it has not pulled — then bd dolt pull is the remedy and is
allowed through, because migrating before that pull is what wedges the clone.
A proxied-server workspace refuses bd dolt pull outright, so there the pull
runs on the server host instead. See
Clone behind the remote. Every other
pending-migration refusal still blocks the pull, so the ordering rule above is
what to plan for.
Back up before you migrate. Schema migrations assume the database matches
the shape the previous migrations left behind; real databases sometimes drift
(interrupted writes, tooling bugs, very old bootstraps). A JSONL export is
cheap, issue-complete, and importable by any bd version:
bd export captures issues, not Dolt history or config — for a full snapshot
also copy the .beads directory (or dolt backup in server mode) while no
bd command is running.
Single clone (including a solo user with a remote):
bd’s remote-migrate gate blocks the run, it prints the available options —
migrating here as the designated migrator, adopting the remote’s already-migrated
database, or recovering a fork — and asks for an explicit operator decision.
Follow the guidance it prints.
For scripted or CI upgrades where nobody reads the output, run
bd migrate schema as an explicit step in exactly one job, never in all of
them. If the gate blocks a run it prints both the available options and the
scripted override that fits the situation.
Multiple clones sharing one remote:
bd dolt pull while the clone has pending migrations. Adopt the
migrated database by re-cloning it. bd bootstrap never replaces an existing
database — run against one, it prints Database already exists and
Nothing to do. and leaves the clone on the old schema — so move the local
database aside first, then re-apply the step 1 backup:
bd export fails. Keep the moved-aside
directory until you have checked the result — the old binary can still open
it. In server mode the database lives under .beads/dolt/ instead; stop the
server and move the database outside .beads/dolt/ (see
re-clone-gotchas).
If a clone was instead migrated independently and bd dolt pull later fails
with cannot merge because table dependencies has different primary keys in its common ancestor, the schema has already forked — follow the recovery playbook:
the pk-fork-refused runbook.
bd doctor includes a migration-content-skew check that flags a forked
schema against the cached remote ref — a useful post-upgrade verification.
It runs in both server and embedded modes.Clone behind the remote
This is the one pending-migration stop whose remedy is abd dolt pull, and
the one the gate links here rather than to the migrate-or-adopt recipe above.
A proxied-server workspace refuses that pull, so it runs on the server host
instead; the last part of this section covers that case.
It fires when the clone is level with the remote on schema but behind it in
data — the remote has commits this clone has not pulled. On schema alone the
clone looks like a safe first-mover, so before
#6575 the gate let it
migrate; the new schema commits then landed on a history missing those
commits, and once a migration moves a tracked table onto Dolt’s ignore plane
every later bd dolt pull refuses to merge
(#6368). The clone can no
longer fetch what it was already behind on.
The remedy is the pull, and nothing else:
bd dolt pull --strategy ours|theirs
on embedded storage / bd conflicts resolve on a server store). Once there is
nothing left to pull, the clone is the first-mover it looked like and the
migration proceeds on its own.
Do not force past this stop. bd migrate --force applies the migration
while the clone is still behind — precisely the state the stop exists to
prevent — and the bd dolt push that would follow is rejected as a
non-fast-forward anyway.
On a shared server, the pull is still the first step, but the migration
after it needs explicit consent, because it promotes the schema for every
co-resident client at once (see Shared servers). Confirm
those clients are upgraded, then:
--force is the consent form here because this stop always has a remote
configured — the behind-ness is read from the remote-tracking ref — and the
bare bd migrate schema consent applies only to a shared database with no
remote. It is safe at this point and only at this point: the pull has already
landed the commits the clone was missing.
In proxied-server mode the database is shared too, so the same two steps
apply, but they run from two places. The workspace refuses bd dolt pull
(proxy.dolt_pull.unsupported) and bd conflicts, so the pull, and any
conflict resolution it needs, runs where the database lives: on the server
host, from a workspace with direct database access. The consent step can then
be run from the proxied workspace, but only once that pull has landed:
bd migrate verb but not bd migrate schema --force, and
BD_ALLOW_REMOTE_MIGRATE=1 grants the same consent to any command. Both are
honored before this stop is reached, so the stop never sees them: run either
one before the pull and it migrates the database while it is still behind.
Do not reach for either to get past the stop.
Shared servers
A server-mode database is served to everybd client connected to that
dolt sql-server, so a schema migration is not a local event: it promotes the
schema version for all of them at once, and clients still running an older
bd refuse the database until they are upgraded too. bd therefore never
auto-migrates a shared database on a version bump — with or without a remote
configured, though the two cases consent differently
(#5920).
Upgrade one server’s clients like this:
bd list stops with
table not found: leases
(#6929). Run step 2 as
soon as the clients are upgraded.
If the shared server also has a Dolt remote, step 2 is not enough. Two
hazards now apply at once — the co-resident lockout above and the cross-clone
fork of Remote-backed databases
— so bd requires the stronger designated-migrator consent it describes:
bd migrate --force, from exactly one machine, followed by bd dolt push. If
another clone has already migrated and pushed, adopt its database instead of
migrating, as described under
Remote-backed databases —
bd bootstrap alone does not replace an existing database. On a shared
server, adopting also promotes the schema for every client of that server, so
step 1 still comes first either way.
A new client joining a server whose schema is behind is refused before its
workspace is written, so there is nothing to run bd migrate schema from
there: do step 2 from a client that is already set up, or join and migrate in
one step with BD_ALLOW_REMOTE_MIGRATE=1 bd init ….
The same rules apply in proxied-server mode, which is a shared server
reached through a local proxy. Three differences worth knowing:
- read commands print a warning and keep serving the current schema, rather than the read simply not touching it;
bd serverefuses to start against a database with pending migrations, because a daemon has no operator to consent for it. Reconcile the schema first with step 2, then start the daemon — or, for an unattended service, putBD_ALLOW_REMOTE_MIGRATE=1in its environment as an explicit, auditable standing consent;- the data-behind stop’s remedy,
bd dolt pull, cannot be run from the proxied workspace: run it on the server host first, then consent from the proxied workspace (see Clone behind the remote).
Cross-era Upgrades
If you’re upgrading from a much older version of bd, inspect the storage layout and metadata before running the current binary. A.beads/dolt/ directory alone
does not identify a legacy workspace: supported current server mode uses that
directory too. Current bd evaluates explicit server metadata, the presence of
that local root, and the bounded .local_version witness together. An explicit
server selection is not overridden by a stale .beads/embeddeddolt/ repository.
The witness is whatever
bd held in its own version string when it last touched
the workspace, so it may be a plain release, a release candidate, a build
carrying metadata, or a Go pseudo-version; all of those are read as the version
they name. A witness that is present but unreadable is not treated as a legacy
marker — no pre-v1 bd could have written one — so bd warns and continues
rather than refusing every command. A missing witness stays ambiguous and is
still refused.
Current bd refuses recognized historical SQLite and legacy Dolt layouts before
opening storage or rewriting metadata. This is intentional: preserve the source
and complete the matching explicit migration below.
PostgreSQL and MySQL are removed backends, not supported cross-era upgrade
paths. Current bd refuses metadata that selects either backend, and the sealed
bridge below accepts SQLite sources only.
.beads/embeddeddolt/: direct upgrade
Upgrade the binary, apply the pending schema migrations, and update the
database metadata:
bd init automatically wired git origin
as the Dolt remote, verify the remote after upgrading:
.beads/config.yaml change so other clones can run
bd bootstrap or bd dolt pull.
Historical Dolt server mode: explicit migration
Do not run currentbd init --force when .beads/dolt/ has missing metadata
or persisted dolt_mode is blank/embedded. Those old embedded layouts are
never current embedded storage. The same explicit path applies when metadata
selects backend: dolt, dolt_mode: server and .local_version records
v0.55.4 through v0.62.0.
First take a native snapshot while every writer is stopped. Restore that
snapshot to a disposable workspace, export it with the verified historical
binary, then import the export into a fresh current project. Keep the original
and snapshot unchanged until the cutover has been reviewed. The SQLite
sealed-copy helper below does not start or manage a Dolt SQL server.
Explicit server metadata with a v0.55.4–v0.62.0 witness is always refused,
including when there is no local .beads/dolt/ root. When that root does exist,
the guard admits explicit server mode only with a syntactically valid witness
whose major version is 1 or newer; a missing, malformed, or pre-v1 witness fails
closed. Without the local root, a missing, malformed, or non-historical witness
is admitted only as a compatibility layout.
The configured shared-server compatibility path applies only when persisted
metadata is missing or leaves dolt_mode blank/embedded; it does not override
an explicit server selection with a local root. Compatibility admission cannot
prove that a workspace is modern. If you know it was created by v0.55.4 through
v0.62.0, use this explicit bridge even when its witness was lost or damaged.
Otherwise, follow the normal bd migrate --dry-run and bd migrate schema
flow for an admitted server workspace.
One .beads/*.db file: sealed SQLite bridge
The old binary stored data in SQLite. The new binary uses Dolt.
Recommended: use the sealed-copy bridge (requires jq):
Stop every process that can write the old workspace before starting.
Run this from a source checkout at the exact commit you intend to run; installed
binaries do not include repository scripts. Record that commit with
git rev-parse HEAD before executing the script. Download the old bd asset
only from the official gastownhall/beads release and verify the asset with its
published SHA-256:
shasum -a 256 on the downloaded archive and compare
the result with that archive’s entry in checksums.txt.