# Reshape Migrations

Zero-downtime database schema migrations using [Reshape](https://github.com/fabianlindfors/reshape).

Reshape is a schema migration tool that uses a 3-phase approach to achieve zero-downtime migrations:

1. **Start**: Creates new schema version with views and triggers. Both old and new schemas are available simultaneously.
2. **Rollout**: Deploy new application code. Services use the new schema via `search_path`.
3. **Complete**: Removes old schema and cleanup artifacts.

## Enabling Reshape

Add a `reshape` block to your postgres definition in `specific.hcl`:

```hcl
postgres "main" {
  reshape {
    enabled = true
  }
}
```

With a custom migrations directory:

```hcl
postgres "main" {
  reshape {
    enabled = true
    migrations_dir = "db/migrations"
  }
}
```

The default migrations directory is `migrations/` relative to `specific.hcl`.

## Automatic Migration Management

When `specific dev` starts with Reshape enabled, migrations are automatically managed:

1. **All migrations except the last one are completed** - These become permanent schema changes
2. **The last migration is started but not completed** - This allows iteration during development
3. **Completed migration files are made read-only** - Prevents accidental modification

This means you can focus on writing migrations without manually running commands.

### File Change Handling

While `specific dev` is running:

- **Modifying the last migration file**: The migration is automatically aborted and restarted. Your services continue running (no restart needed since the schema name doesn't change).

- **Adding a new migration file**: The previous migration is completed (made permanent), and the new migration is started. Services are automatically restarted to use the new schema.

## Connection Strings

When Reshape is enabled, `postgres.<name>.url` automatically includes the correct `search_path` option. You don't need to change your service configuration:

```hcl
service "api" {
  build = build.api
  command = "node server.js"

  env = {
    DATABASE_URL = postgres.main.url  # Automatically includes search_path
  }
}
```

## Writing Migrations

Place migration files in your migrations directory. Files are processed in **lexical order** (e.g., `001_first.toml` before `002_second.toml`).

**IMPORTANT:** You MUST run `specific check` every time you create or edit a migration file. This validates both your `specific.hcl` configuration and all migration files, catching errors before the watcher applies them. Without this step, invalid migrations will silently fail to apply.

```bash
# Validate specific.hcl and all migration files
specific check
```

Example migration (`migrations/001_create_users.toml`):

```toml
[[actions]]
type = "create_table"
name = "users"
primary_key = ["id"]

  [[actions.columns]]
  name = "id"
  type = "INTEGER"
  generated = "ALWAYS AS IDENTITY"

  [[actions.columns]]
  name = "email"
  type = "TEXT"
  nullable = false
```

For full documentation on available actions and migration syntax, see [Actions](/postgres/reshape/actions).

## Manual Migration Commands

You can also manually control migrations using the `specific reshape` command:

```bash
# Validate migration files (does NOT require specific dev to be running)
specific reshape check

# Start a migration (applies new schema while keeping old one available)
specific reshape start

# Start migration on a specific database
specific reshape start main

# Check migration status
specific reshape status main

# Complete a migration (removes old schema)
specific reshape complete main

# Abort a migration (rolls back to old schema)
specific reshape abort main
```

**Note:** Most commands require `specific dev` to be running as they need access to the database. The `check` command is an exception - it only validates migration file syntax and can be run anytime.

## Development Workflow

1. Write your migration file in the migrations directory
2. Run `specific check` to validate both `specific.hcl` and migration syntax
3. `specific dev` automatically applies it
4. Iterate on the migration - run `specific check` after **every** change
5. When ready, add a new migration file to "lock in" the previous one

**Remember:** Always run `specific check` after any change to a migration file or `specific.hcl`. This validates everything in one step.

Completed migrations are made read-only to prevent accidental changes. If you need to modify a completed migration, you'll need to manually change the file permissions first.

---

Related topics:
- Run `specific docs /postgres/reshape/actions` for available migration actions
- Run `specific docs /postgres` for general PostgreSQL documentation
- Run `specific docs /sync` for real-time data synchronization
