## TL;DR
Old migration files are not stale: they are the only path from an empty database to the current schema, and every environment's history references them. Restore the deleted files from version control, prove a fresh database bootstraps from zero, and set the team rule: applied migration files are immutable and never deleted. Squash deliberately instead of deleting casually.

## The query

```text
agent deleted old migration files thinking they were stale - now new environments cant bootstrap
```

## Use this when

- Deleted migration files broke new environment bootstrap
- Fresh database cannot migrate from zero
- Old migration files thought to be stale
- An agent pruned migration history

## Not for

- Files that never applied anywhere (deleting those is safe, with care)
- A deliberate squash (do the squash properly, keep the old files until every environment passes them)
- Corrupt migration files (fix or replace them, do not just delete)

## Steps

### 1. Restore the deleted files

```bash
git log --diff-filter=D --name-only -- [migrations dir]/
git checkout [commit before deletion] -- [migrations dir]/
```

Expected output: the files are back with their original content. Restore all of them: a partial restore leaves a different hole.

### 2. Prove fresh bootstrap works

On an empty database, run the full migration chain from zero:

```bash
alembic upgrade head
```

(or the tool's equivalent). Expected output: the chain completes and the schema matches production. This is the test the deletion broke; it must pass now.

### 3. Check every environment's history still resolves

For each environment (prod, staging, dev databases), verify its recorded versions all have files: alembic history, flyway validate, or the tool's check. Expected output: no "missing revision" or "not resolved locally" errors anywhere.

### 4. Set the immutability rule

Applied migration files are never deleted, period. The runbook states it; code review enforces it; a CI check can flag deletions under the migrations directory.

Expected output: the next "cleanup" instinct meets a rule that says no.

### 5. Squash deliberately when history gets long

If the real complaint is a long chain, do a proper squash: new baseline migration, old files kept until every environment has passed the squash point, schema equivalence proven on scratch. Expected output: a shorter chain achieved without breaking any environment's history.

## Tool compatibility

alembic, flyway, django, rails, prisma, dbmate: every tool needs its history files to bootstrap fresh databases.

## Variant phrasings

### deleted old migration files new environments cant bootstrap

Steps 1 and 2: restore from git, prove fresh bootstrap from zero.

### migration files deleted thinking stale

Step 4: applied files are immutable. "Stale" is not a concept that applies to migration history.

### squash vs delete old migrations

Step 5: squash deliberately with equivalence proof; never delete casually.

## Why it happens

Migration files serve two masters: existing databases (which need the files their history references) and new databases (which replay the whole chain from zero). Deleting "old" files breaks both: existing environments lose resolvable history, and new environments have no path to the current schema. The files look stale because they already ran; that is exactly what makes them load-bearing.

## Edge cases

- A partial restore (some files back, some still missing) produces confusing half-errors: restore everything the deletion removed, then verify.
- If the deletion also shipped to production's history (someone "cleaned" prod), the restore must happen before any new migration runs there, or the chain forks.
- Files that never applied anywhere are genuinely deletable: verify "never applied" against every environment's history table, not just prod.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_lmdvRslYdJ03zkddWtrDyQ
