Skip to main content
migration:up keeps a per-version run cache so a migration whose code is unchanged since its last successful apply is skipped without touching the database. The database migrations table stays the source of truth for what has been applied; the cache is only a fast path. When every registered migration is already recorded and unchanged, the runner skips opening a database connection altogether and prints an up to date (cached) line for each.

What the cache stores

One JSON file per applied version lives under var/cache/migrations/ at the project root, so editing a single migration invalidates only that migration’s entry. Each entry records the cache version, the migration id, a fingerprint hash, and the time it was applied. Only successful applies are written, and the directory is safe to delete at any time.

How an entry is fingerprinted

The hash covers the migration’s version, the target table name, the target database URL, and the source of its up() and down() methods. Any change to the migration’s code — or pointing at a different database or table — yields a new hash and therefore a cache miss, so the migration is re-checked against the tracking table and run if pending.

When the cache is bypassed

TriggerEffect
--dropThe database is reset, so a cache hit would wrongly skip the rebuild; the cache is bypassed and every migration re-runs.
--no-cacheExplicit escape hatch — reads and writes are skipped for the run.
migration:downA rollback deletes the rolled-back version’s cache entry, so the next migration:up re-applies it instead of treating it as up to date.
Like any cache decoupled from live database state, an entry can go stale if the database is reset out of band — --drop and --no-cache exist for exactly that case.

Next steps