Use Queen as a Library
Use the library API when migrations should run from your application startup, tests, or an internal deploy tool.
Create a Queen instance
db, err := sql.Open("pgx", os.Getenv("DATABASE_URL"))
if err != nil {
return err
}
defer db.Close()
q := queen.New(postgres.New(db))
defer q.Close()
queen.New accepts options:
q := queen.New(
postgres.New(db),
queen.WithLogger(logger),
queen.WithTap(tap.NewJSONSink(os.Stdout)),
)
Configure behavior
q := queen.NewWithConfig(postgres.New(db), &queen.Config{
TableName: "queen_migrations",
LockTimeout: 10 * time.Minute,
SkipLock: false,
})
Use SkipLock: true only for controlled single-runner cases. For production PostgreSQL, keep locking enabled.
Config fields:
| Field | Default | Purpose |
|---|---|---|
TableName | queen_migrations | Migration metadata table. |
LockTimeout | 30m | Driver lock acquisition timeout. |
SkipLock | false | Skip driver lock acquisition. |
Naming | nil | Optional version naming policy. |
IsolationLevel | sql.LevelDefault | Default transaction isolation level. |
Register migrations
func Register(q *queen.Queen) {
q.MustAdd(queen.M{
Version: "001",
Name: "create_users",
UpSQL: `CREATE TABLE users (id SERIAL PRIMARY KEY, email TEXT NOT NULL);`,
DownSQL: `DROP TABLE users;`,
})
}
MustAdd is convenient during program startup. Use Add if you want to return registration errors instead of panicking.
Apply and rollback
err := q.Up(ctx) // apply all pending migrations
err = q.UpSteps(ctx, 2) // apply up to 2 pending migrations
err = q.Down(ctx, 1) // rollback one migration
err = q.Reset(ctx) // rollback all applied migrations
Down(ctx, n <= 0) rolls back exactly one latest migration. Use Reset(ctx) for "everything".
Inspect before running
plans, err := q.DryRun(ctx, queen.DirectionUp, 0)
if err != nil {
return err
}
for _, p := range plans {
fmt.Printf("%s %s destructive=%v\n", p.Version, p.Name, p.IsDestructive)
}
Validate(ctx) checks registration validity and applied checksum drift before you run migrations.
Runtime API
| Method | Purpose |
|---|---|
Add(m queen.M) error | Register one migration. |
MustAdd(m queen.M) | Register one migration and panic on invalid input. |
Up(ctx) | Apply all pending migrations. |
UpSteps(ctx, n) | Apply up to n pending migrations; n <= 0 means all. |
Down(ctx, n) | Roll back n latest migrations; n <= 0 means one. |
Reset(ctx) | Roll back all applied migrations. |
Status(ctx) | Return status for all registered migrations. |
Validate(ctx) | Validate registration and checksum drift. |
DryRun(ctx, direction, limit) | Return migration plans without executing. |
Explain(ctx, version) | Return detailed plan for one migration. |
FindMigration(version) | Return a defensive copy of one registered migration. |
Driver() | Return the underlying driver. |
SQLDB() | Return the underlying *sql.DB when the driver exposes it. |
Close() | Close driver resources. |
Long-running public operations on a single Queen instance are serialized internally. For production deploys, still run one intentional migrator job per environment.
Status values
Status(ctx) reports:
| Status | Meaning |
|---|---|
pending | Registered in code, not recorded in the database. |
applied | Registered and recorded with matching checksum. |
modified | Applied, but the registered SQL checksum differs from the stored checksum. |
modified blocks migration execution until you resolve the drift.
pgxpool adapter
If your app already owns a pgxpool.Pool, use the adapter:
pool, err := pgxpool.New(ctx, os.Getenv("DATABASE_URL"))
if err != nil {
return err
}
defer pool.Close()
q := queen.New(postgres.NewFromPool(pool))
defer q.Close()
Closing Queen closes the database/sql adapter handle, not the caller-owned pool.
Testing helper
Queen includes a small test helper:
func TestMigrations(t *testing.T) {
driver := setupTestDriver(t)
q := queen.NewTest(t, driver)
migrations.Register(q.Queen)
q.TestUpDown()
}
Useful helper methods include MustUp, MustDown, MustReset, MustValidate, TestUpDown, and TestRollback.