The model layer
Migrations record every schema change as reviewable SQL. Use them whenever you add
or change a model: run makemigrations, review the SQL, then run migrate.
GORM runs your queries at runtime. It never replaces recorded history with
AutoMigrate.
#Ask your agent
Read https://cicadel.fauzaanu.com/en/dev/topics/migrations/index.md.
Add [model or schema change] through the application's registered Models and
recorded PostgreSQL history. Generate and review SQL, test against a disposable
database, and report the plan before touching an existing production database.
Do not use AutoMigrate or rewrite applied migration files.#How it works
- You register models in your app’s
Models(). makemigrationscompares them with the recorded history and writes a new SQL file.- You review the SQL, commit it and rebuild the application.
migrateapplies pending files to PostgreSQL and records what it applied.
The first-party contrib/migrations module does the work: generation, historical
state, version dependencies, execution, verification and recovery. The standard
management commands use it.
#Add a model
startproject already includes accounts, formsets, the migration commands and
typed query generation. startapp blog creates an app with:
- a
Models()function, - a
MigrationDirectory, - an embedded migration filesystem.
Register blog.New() in project/apps.go. Keep the existing first-party
registrations.
Then add and register a model in apps/blog/models.go:
package blog
import "github.com/fauzaanu/cicadel"
type Note struct {
ID int64 `gorm:"primaryKey"`
Title string `gorm:"not null"`
}
func (Note) TableName() string { return "blog_notes" }
func Models() []cicadel.Model {
return []cicadel.Model{cicadel.ModelOf[Note]("note", "blog_notes")}
}#Generate and apply
From the project root:
go run manage.go makemigrations blog --name initial
go run manage.go makemigrations blog --check
go run manage.go generatequeries
DATABASE_URL='postgres://.../app' go run manage.go migrate plan
DATABASE_URL='postgres://.../app' go run manage.go migrate
DATABASE_URL='postgres://.../app' go run manage.go migrate verify
DATABASE_URL='postgres://.../app' go run manage.go showmigrations| Command | What it does | Needs PostgreSQL |
|---|---|---|
makemigrations APP --name NAME | Writes the next SQL file into the app’s migration directory. | No |
makemigrations APP --check | Fails when model changes need a migration. Writes no files. | No |
generatequeries | Generates typed query files. | No |
migrate plan | Lists the steps migrate would run. | Yes |
migrate | Applies pending migrations. | Yes |
migrate verify | Checks that the database schema matches the applied history. | Yes |
showmigrations | Lists each migration as applied or pending. | Yes |
Generation compares registered models with the recorded historical state. It never
reads a developer’s database. It runs offline, even when DATABASE_URL points to
an unavailable server. So app factories used by InstalledApps(nil) must not do
database work.
After generating:
- Review the generated SQL and query files.
- Commit them.
- Build the application again, so its embedded history is current.
#Model registration
Migrations and typed queries share one public ModelOf registry. It holds model
names, types and table ownership. Each declared table must match GORM’s table name.
Configure these in project/migrations.go through
management.ModelMigrationOptions:
- pinned cross-app historical references,
- naming strategies,
- custom type mappings.
Renames, removals, conversions and backfills must be declared explicitly. Use
makemigrations APP --changes changes.json. See the
operation contract.
#Core module composition
The migration engine is a core default shipped as an installable Go module. Standard projects already include its management commands.
- Register models and migration sources through the app contract.
- Generate package-owned migrations in the package’s source checkout.
- Application builds load recorded history from the embedded filesystem.
Use the same framework version for the CLI and the application. Recorded migrations and history from any release keep working with later releases. See the data guarantee.
#Recovery
Management commands load every registered migration source into one dependency catalog. They use the runner’s shared PostgreSQL lock. Register every app whose applied history you manage.
| Task | Command |
|---|---|
| Review a target version | migrate plan --target APP=VERSION |
| Roll back deliberately, after review | migrate apply --target APP=VERSION --allow-data-loss |
| Verify an eligible pre-existing initial schema | migrate baseline --reason TEXT |
| Recover a nontransactional index migration | migrate recover --migration APP:VERSION --recovery retry|complete |
Warning
Migration history is not a data backup.
Unsupported changes fail explicitly. See the supported PostgreSQL operations and the acceptance evidence.