Migrations are plain Go values listed in one registry function. There is no init() registration: vukem make:migration writes the file and appends it to the list.
Creating a migration#
vukem make:migration create_comments_table
vukem make:migration add_slug_to_posts_tableThe stub depends on the name: create_<table>_table creates a table, add_x_to_<table>_table / alter_<table>_table alter one, anything else is blank.
func m20261016120000CreateCommentsTable() schema.Migration {
return schema.Migration{
ID: "20261016120000_create_comments_table",
Up: func(s *schema.Schema) error {
return s.Create("comments", func(t *schema.Table) {
t.ID()
t.ForeignID("post_id").Constrained().CascadeOnDelete()
t.Text("body")
t.Boolean("approved").Default(false)
t.Timestamps()
t.Index("post_id", "approved")
})
},
Down: func(s *schema.Schema) error { return s.DropIfExists("comments") },
}
}func All() []schema.Migration {
return []schema.Migration{
m20260101000000CreatePostsTable(),
m20261016120000CreateCommentsTable(), // appended by make:migration
}
}bootstrap.New passes migrations.All() to vukem.WithMigrations.
Schema builder#
Schema | Table columns | Column modifiers |
|---|---|---|
Create, Table (alter), Drop, DropIfExists, Rename, HasTable, Raw | ID, String(name, len?), Text, Integer, BigInteger, Boolean, Decimal(p, s), Float, Date, Timestamp, Timestamps, SoftDeletes, JSON, UUID, ULID, Binary, Enum(name, values...), ForeignID | Nullable, Default, Unique, Index, Constrained(table?), CascadeOnDelete, NullOnDelete, RestrictOnDelete |
Altering: t.RenameColumn(from, to), t.DropColumn(names...), t.Index(cols...), t.UniqueIndex(cols...), t.DropIndex(name).
DDL is generated per dialect (SQLite and PostgreSQL). Table and column names are validated, never taken from user input.
Running migrations#
| Command | Effect |
|---|---|
vukem migrate | Run pending migrations in one batch |
vukem migrate:rollback [--step N] | Roll back the last batch, or the last N migrations |
vukem migrate:reset | Roll back everything |
vukem migrate:fresh | Drop all tables and re-run every migration |
vukem migrate:status [--json] | Which migrations ran, in which batch, and when |
migrate:reset and migrate:fresh refuse to run with APP_ENV=production unless --force is given.
Each applied migration stores a checksum of the SQL it produced. migrate:status flags migrations whose SQL changed after they ran and migrations recorded in the database but missing from code.
In code, app.Migrator() returns a *schema.Migrator with Up, Rollback, Reset, Fresh and Status; vukemtest.New uses it to migrate the test database.