Cross-environment migration sync

voltro db plan --against <env-url> — diff your local declared schema against a remote env's live DB before pushing, over the framework's inspect endpoint. No DB connection from the CLI.

voltro db plan --against <url> fetches a remote environment's live schema via the framework's /_voltro/inspect/migrations endpoint and diffs it against your LOCAL declared schema — a "what would my branch do if I shipped it to staging right now?" pre-deploy preview. No database connection from the CLI to the remote; everything goes through HTTP.

How it works

  1. Fetch /_voltro/inspect/migrations on the remote URL.
  2. Unwrap the Inspect Observation and read data.drift.liveSnapshot — the same SchemaSnapshot shape introspectSchema produces locally. The drift payload carries it alongside the fingerprints (liveFingerprint, lastAppliedFingerprint).
  3. Run the planner against (local-declared, remote-live).
  4. Render the plan output marked with the remote URL so you know it's not a local diff:
[--against https://staging.example.com/_voltro/inspect/migrations] — diff vs remote live schema:

schema diff: 3 operations, 0 blocked

  ✓ CREATE INDEX users_email_lower_idx ON users (lower("email"))
  ✓ ALTER TABLE posts ADD COLUMN searchVec tsvector ...
  ✓ CREATE INDEX posts_search_gin ON posts (searchVec)

The exit code is 2 when the plan has blocked ops, 0 otherwise — so a CI job can gate a deploy on a clean diff against the target env. An HTTP failure, missing snapshot or explicitly incomplete observation returns 1 without computing a plan. Scope, origin and completeness accompany a successful observation in the log; one answering replica is not evidence that every replica has the same schema.

Auth

The inspect endpoint accepts a bearer token:

voltro db plan --against https://prod.example.com --token $PROD_INSPECT_TOKEN

Without --token, the CLI reads the VOLTRO_INSPECT_TOKEN env var. Without either, the request goes unauthenticated and the standard inspect gate refuses it with 401. An unset server token does not open that gate.

The token is the same one the remote app boots with:

# On the remote side:
VOLTRO_INSPECT_TOKEN=<secret> voltro serve

See Introspection for the full auth configuration.

URL shape

The CLI accepts either form:

voltro db plan --against https://staging.example.com
voltro db plan --against https://staging.example.com/_voltro/inspect/migrations

If the URL doesn't end in /_voltro/inspect/migrations, the CLI appends it. The trailing-slash variant works too.

CLI flags

Flag Required Description
--against yes URL of the remote env (base URL OR full inspect URL)
--token no Bearer token. Falls back to VOLTRO_INSPECT_TOKEN env

See also