Migrations
Steward versions schema changes the boring, reliable way: ordered
migrations with batches and rollback — not AutoMigrate drift. The public
migrate package depends only on GORM.
Writing migrations
A migration is Go code — full access to your models and to raw SQL:
// migrations/20260728120000_add_featured.go
package migrations
import (
"gorm.io/gorm"
"github.com/imfiqhan/steward/migrate"
)
func init() {
All = append(All, migrate.Migration{
Name: "20260728120000_add_featured",
Up: func(tx *gorm.DB) error {
return tx.Exec(`ALTER TABLE posts ADD COLUMN featured boolean NOT NULL DEFAULT false`).Error
},
Down: func(tx *gorm.DB) error {
return tx.Exec(`ALTER TABLE posts DROP COLUMN featured`).Error
},
})
}steward make:migration add_featured scaffolds the file with a timestamped
name; steward make:resource writes the table-creation migration for you.
Each migration runs in a transaction; a failure rolls back and stops the
run.
Running them
go run . migrate up # apply everything pending (one batch)
go run . migrate status # source, name, batch, applied-at
go run . migrate down # roll back the last batch
go run . migrate down -steps 2 # or exactly N migrationsApplied state lives in the admin_migrations table with two sources:
core (Steward’s own tables — users, roles, permissions, menu, logs,
settings) and app (yours). Core migrations also seed the first
admin / admin account and the default menu.
Production
By default Build() applies pending core migrations so development “just
works”. For production, take control:
steward.New(steward.Config{ ..., DisableAutoMigrate: true })and run ./app migrate up as an explicit release step, before the new
serve/worker processes start.