Skip to main content

Project Structure

Queen migrations are Go code, so the cleanest layout is a normal Go package for migrations plus a small CLI entrypoint.

myapp/
cmd/
migrate/
main.go
migrations/
migrations.go
001_create_users.go
002_add_user_slug.go
003_backfill_profiles.go
go.mod

Migration registry

migrations/migrations.go
package migrations

import "github.com/yaop-labs/queen"

func Register(q *queen.Queen) {
Register001CreateUsers(q)
Register002AddUserSlug(q)
Register003BackfillProfiles(q)
}

SQL migration file

migrations/001_create_users.go
package migrations

import "github.com/yaop-labs/queen"

func Register001CreateUsers(q *queen.Queen) {
q.MustAdd(queen.M{
Version: "001",
Name: "create_users",
UpSQL: `
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
`,
DownSQL: `DROP TABLE users;`,
})
}

Go-function migration file

migrations/003_backfill_profiles.go
package migrations

import (
"context"
"database/sql"

"github.com/yaop-labs/queen"
)

func Register003BackfillProfiles(q *queen.Queen) {
q.MustAdd(queen.M{
Version: "003",
Name: "backfill_profiles",
ManualChecksum: "backfill-profiles-v1",
UpFunc: up003BackfillProfiles,
})
}

func up003BackfillProfiles(ctx context.Context, tx *sql.Tx) error {
_, err := tx.ExecContext(ctx, `
INSERT INTO profiles (user_id, display_name)
SELECT id, email FROM users
`)
return err
}

CLI entrypoint

cmd/migrate/main.go
package main

import (
"github.com/yaop-labs/queen/cli"
"myapp/migrations"

_ "github.com/jackc/pgx/v5/stdlib"
)

func main() {
cli.Run(migrations.Register)
}

This gives you one migration registry reused by:

  • local development through go run ./cmd/migrate ...;
  • CI/CD through a built migrator binary;
  • application startup if your app calls Queen directly.

A complete copy-paste version of this layout lives in examples/basic-migrator in this documentation repo. For the runtime model behind this layout, see Architecture. For database-specific migration examples, see Database Examples.