| name | db-migrations |
| description | Create, run, and rollback database migrations using goose or golang-migrate. Trigger: when running database migrations, creating migration files, rolling back migrations, using goose, using golang-migrate |
| version | 1 |
| argument-hint | [up|down|status|create <name>] |
| allowed-tools | ["bash","read","write","grep","glob"] |
Database Migrations
You are now operating in database migration mode.
Goose (Recommended for Go Projects)
Installation
go install github.com/pressly/goose/v3/cmd/goose@latest
Create Migrations
goose -dir migrations create add_users_table sql
goose -dir migrations create backfill_user_roles go
This creates timestamped files like migrations/20260310120000_add_users_table.sql.
SQL Migration File Format
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_users_email ON users(email);
DROP TABLE IF EXISTS users;
Running Migrations
goose -dir migrations postgres "postgresql://postgres:dev@localhost:5432/myapp" up
goose -dir migrations postgres "postgresql://postgres:dev@localhost:5432/myapp" up-by-one
goose -dir migrations postgres "postgresql://postgres:dev@localhost:5432/myapp" down
goose -dir migrations postgres "postgresql://postgres:dev@localhost:5432/myapp" down-to 20260310000000
goose -dir migrations postgres "postgresql://postgres:dev@localhost:5432/myapp" redo
goose -dir migrations postgres "postgresql://postgres:dev@localhost:5432/myapp" status
SQLite with Goose
goose -dir migrations sqlite3 "./app.db" up
goose -dir migrations sqlite3 "./app.db" status
Goose in Go Code (Embedded)
import (
"embed"
"database/sql"
"github.com/pressly/goose/v3"
)
var migrations embed.FS
func runMigrations(db *sql.DB) error {
goose.SetBaseFS(migrations)
if err := goose.SetDialect("postgres"); err != nil {
return err
}
return goose.Up(db, "migrations")
}
golang-migrate
Installation
go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
Create Migrations
golang-migrate uses paired files: one for up, one for down.
migrate create -ext sql -dir migrations -seq add_users_table
Running Migrations
migrate -path migrations -database "postgresql://postgres:dev@localhost:5432/myapp?sslmode=disable" up
migrate -path migrations -database "..." down 1
migrate -path migrations -database "..." goto 3
migrate -path migrations -database "..." version
Simple SQL Migration Pattern (No Tool)
For small projects without a migration tool:
mkdir -p migrations
for f in migrations/*.sql; do
psql "$DATABASE_URL" -f "$f"
echo "Applied: $f"
done
Best Practices
- Always write a
Down migration that perfectly reverses the Up.
- Test the rollback locally before merging.
- Never edit a migration that has already been applied to production.
- Use transactions in SQL migrations when the database supports them.
- Keep migrations small and focused — one logical change per migration.
- Run
status before up in CI to confirm the expected state.
Migration Status Check
goose -dir migrations postgres "$DATABASE_URL" status