## TL;DR
The schema_migrations table lists versions whose files are gone, usually deleted files or a branch switch. Compare the table against the db/migrations directory, restore the missing files from version control when the migrations are real, and only delete history rows when you are certain the migration never ran anywhere real. Verify with dbmate status afterwards.

## The query

```text
dbmate error: current schema is ahead of the migration files - how to reconcile
```

## Use this when

- dbmate reports the schema is ahead of the migration files
- schema_migrations has versions with no file on disk
- Migration files were deleted or the branch changed
- An agent pruned "old" migration files

## Not for

- A database behind the files (run dbmate migrate)
- A migration that fails while applying (fix the SQL)
- dbmate dump discrepancies (schema.sql is a snapshot, not history)

## Steps

### 1. List the versions with no file

```bash
dbmate status
```

And compare directly:

```sql
SELECT version FROM schema_migrations ORDER BY version;
```

Expected output: the versions recorded in the table that have no matching file in db/migrations. That list is the entire problem.

### 2. Check version control for the missing files

```bash
git log --diff-filter=D --name-only -- db/migrations/ | head -20
```

Expected output: the deleted filenames and the commits that removed them. If git has them, restoration is the safe path.

### 3. Case A: the migrations are real - restore the files

```bash
git checkout [commit before deletion] -- db/migrations/[file].sql
```

Expected output: every recorded version resolves to a file again, and dbmate status is clean.

### 4. Case B: the migration never ran anywhere real - remove the row

```sql
DELETE FROM schema_migrations WHERE version = '[orphaned version]';
```

Only when the migration's effects are verifiably absent from every database (its objects do not exist) and the deletion was deliberate. Expected output: the history matches the files again.

### 5. Verify and protect the directory

```bash
dbmate status
```

Expected output: no "ahead of the migration files" warning. Add the team rule: applied migration files are never deleted; squashes keep the old files until every environment has passed them.

## Tool compatibility

dbmate 1.x and 2.x. schema_migrations bookkeeping and status output are the same.

## Variant phrasings

### dbmate current schema is ahead of the migration files

Steps 1 through 3: list orphans, restore from git.

### dbmate status schema ahead how to reconcile

Step 4 only for migrations that never ran anywhere real: delete the row after verifying the objects are absent.

### dbmate deleted migration file but applied

Step 3: restore it. dbmate has no checksums, but the file is the only record of what the version did.

## Why it happens

dbmate tracks applied migrations as version strings in schema_migrations and resolves them against files at status time. A recorded version with no file means history references work that no longer exists on disk, so dbmate warns instead of proceeding on a history it cannot fully read.

## Edge cases

- dbmate schema.sql dumps can confuse this: the dump is a snapshot, not the file list. The check is table versions versus db/migrations files, nothing else.
- If the missing file applied in production, restore it even if the team considers it "old": production's history must stay readable.
- When two databases legitimately need different histories, they need different migration directories, not deletions from a shared one.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_7-CMFHoI6qrzRNoPUC09xw
