Migrations
Auto vs. explicit, when to switch.
Grit's default migration strategy is GORM AutoMigrate: run it on boot, GORM reconciles the schema with your struct definitions. Magical when it works. This lesson covers when to keep it and when to switch.
What AutoMigrate does
db.AutoMigrate(&models.User{},&models.Customer{},&models.Invoice{},&models.LineItem{},)
For each struct, GORM:
- Creates the table if it doesn't exist
- Adds new columns when you add struct fields
- Adds new indexes when you add new
gorm:"index"tags - Adds new foreign keys when you add relations
What AutoMigrate doesn't do
- Remove columns â you can delete a struct field but the column lingers. Manual
ALTER TABLE DROP COLUMN. - Rename columns â it would see the rename as "drop A, add B" and lose data. Use raw SQL with a manual rename.
- Change column types â only certain narrowings work; widening usually does, narrowing rarely does.
- Data migrations â backfilling values when a new column lands. AutoMigrate handles schema; YOU handle data.
Running migrations explicitly
Grit ships grit migrate as a CLI command that calls AutoMigrate on the same model list. In production:
# in your deploy script, BEFORE starting the new API binary$grit migrate# then start the API$./api-binary
This way the migration only runs once per release (not per worker on boot), and a failed migration aborts the deploy before serving traffic.
When to switch to explicit migrations
- You need to do data migrations (backfills, splits, joins)
- You need to rename columns without dropping data
- You ship to customers who self-host (they need versioned migrations they can roll back)
- You need a review trail â explicit SQL files in git that's reviewable
The graduation path: add golang-migrate/migrate or pressly/goose, put SQL files in internal/database/migrations/, run them from a CLI. Grit doesn't prescribe one â pick what fits your team.
The pragmatic middle: AutoMigrate + occasional raw SQL
Most Grit projects start with AutoMigrate, then run an occasional manual ALTER TABLE for renames + drops. That's fine for teams of 1â5 with a clear deploy process.
Quick check
Try it
Trigger the rename gotcha on your bench-api:
- In your
Invoicemodel, rename a field â e.g.,TotalâTotalAmount. - Run
grit migrate. - Open GORM Studio and look at the invoices table. You'll see both columns.
- In
notes.md, write the SQL you'd run to consolidate: copy data + drop old column.
What's next
Chapter 3 â Auth + RBAC. JWT, OAuth2, TOTP 2FA, and role-based gating. The heaviest chapter, the highest leverage.
Spot a typo? Have an idea?
Help us improve this lesson. One click opens a GitHub issue with the lesson URL pre-filled â suggest clearer wording, report a bug, or request more depth. The course keeps improving thanks to learners like you.
Suggest an improvement on GitHub