> ## Documentation Index
> Fetch the complete documentation index at: https://bunny.net/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Database Migrations

> Version your Bunny Database schema with SQL migration files applied by the Bunny CLI.

Schema changes have to reach every environment in the order you wrote them. `bunny db migrations` keeps those changes as plain `.sql` files in your repository, applies them in filename order, and records what has run so the same file never applies twice.

> [!NOTE]
>
> Bunny Database is currently in [Public
> Preview](/docs/product-release-stages#stage-2-public-preview). Features and APIs
> may evolve during this period.

## Prerequisites

* The [Bunny CLI](/docs/cli/installation) installed, and `bunny login` completed
* A database. If you don't have one, [create one](/docs/database/quickstart)

Migration commands resolve their target the same way the rest of `bunny db` does, so run `bunny db link` once in your project and every command below works without a database ID. See [database resolution](/docs/cli/commands/db#database-resolution) for the full order.

## Quickstart

**1. Create a migration**

```bash theme={null}
bunny db migrations create add_users_table
```

The CLI writes `migrations/0001_add_users_table.sql`. That filename is the migration's identity and it sets the order the migration runs in, so leave it alone once you've applied it.

**2. Write the SQL**

The new file holds a comment and nothing else. Add your statements to it:

```sql migrations/0001_add_users_table.sql theme={null}
CREATE TABLE users (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL,
  email TEXT UNIQUE NOT NULL
);
```

`apply` rejects a migration with no statements, so an empty file can't record itself as done.

**3. Preview what will run**

```bash theme={null}
bunny db migrations apply --dry-run
```

A dry run reads your files and the recorded history, prints the migrations it would run, and writes nothing to the database.

**4. Apply the migrations**

```bash theme={null}
bunny db migrations apply
```

Pending migrations run in filename order. The CLI sends each file as one atomic batch together with its tracking row, so a migration either lands and gets recorded or neither happens. It also defers foreign keys for the batch, which is what makes table rebuilds work.

A failing migration stops the run and leaves everything after it pending.

**5. Check the history**

```bash theme={null}
bunny db migrations list
```

## How migrations are tracked

The CLI records each applied migration in a `__bunny_migrations` table, along with a checksum of the file it applied. The `__` prefix keeps that table out of [studio](/docs/cli/commands/db#bunny-db-studio) and REST introspection, so it stays out of your way when you browse the schema.

`bunny db migrations list` only ever reads, and it never creates the tracking table, so you can check a database's state without changing it.

## Migration states

`list` reports every migration in one of five states:

| State | Meaning |
| - | - |
| `Applied` | On disk and recorded, with matching checksums |
| `Pending` | On disk, with no record of a run |
| `Modified` | Recorded, and the file has changed since it ran |
| `Missing` | Recorded, and the file has gone from disk |
| `Out of order` | Pending, and sorts before a migration that already ran |

The last three are drift: your files and the database disagree about what has happened. Drift usually means someone edited or deleted an applied migration, or a branch introduced a migration numbered below one that production has already run.

`apply` refuses to run against a drifted history and changes nothing. Fix the files where you can. When the drift is expected, say you rewrote history on a development database on purpose, `--allow-drift` applies anyway:

```bash theme={null}
bunny db migrations apply --allow-drift
```

## Use with an ORM

If your ORM already generates SQL migration files, point `apply` at its output directory and skip writing migrations by hand. The CLI falls back to `drizzle/` when a `migrations/` directory doesn't exist and you pass no `--dir`, so [drizzle-kit](https://orm.drizzle.team/docs/kit-overview) output works with no configuration:

```bash theme={null}
drizzle-kit generate
bunny db migrations apply
```

For any other layout, name the directory and the glob:

```bash theme={null}
# Explicit directory
bunny db migrations apply --dir drizzle

# One SQL file per subdirectory
bunny db migrations apply --dir drizzle --pattern "*/migration.sql"
```

`bunny db migrations create` never writes into an ORM's output directory, even when it detects one. A hand-authored file there would bypass the ORM's own journal and the two would drift apart.

## Run migrations in CI

`apply` prompts for confirmation only when stdin is an interactive terminal, so a CI job won't hang waiting on an answer. Pass credentials directly to skip the API lookup and token generation:

```bash theme={null}
bunny db migrations apply \
  --url "$BUNNY_DATABASE_URL" \
  --token "$BUNNY_DATABASE_AUTH_TOKEN" \
  --force
```

The CLI parses every migration file before the first write, so a malformed file near the end of the run fails the job before anything reaches the database.

## Command reference

See [`bunny db migrations`](/docs/cli/commands/db#bunny-db-migrations) for every subcommand, flag, and alias.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.