cicadel

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

Text
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

How Cicadel migrations flow from models to PostgreSQLModels registered in models.go go to makemigrations, which writes a reviewable SQL file into the app's migrations directory. The SQL file records the model state that the next makemigrations compares against. You commit the file and build it into the application. migrate applies it to PostgreSQL and records each applied version and checksum in the history tables.models.goModels()makemigrationsofflineSQL file00001_initial.sqlmigrateplan · applyPostgreSQLschemaHistoryversions · checksumsrecordedreview · commit · buildrecorded model state feeds the next run

  1. You register models in your app’s Models().
  2. makemigrations compares them with the recorded history and writes a new SQL file.
  3. You review the SQL, commit it and rebuild the application.
  4. migrate applies 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:

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:

Terminal
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
CommandWhat it doesNeeds PostgreSQL
makemigrations APP --name NAMEWrites the next SQL file into the app’s migration directory.No
makemigrations APP --checkFails when model changes need a migration. Writes no files.No
generatequeriesGenerates typed query files.No
migrate planLists the steps migrate would run.Yes
migrateApplies pending migrations.Yes
migrate verifyChecks that the database schema matches the applied history.Yes
showmigrationsLists 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:

  1. Review the generated SQL and query files.
  2. Commit them.
  3. 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.

TaskCommand
Review a target versionmigrate plan --target APP=VERSION
Roll back deliberately, after reviewmigrate apply --target APP=VERSION --allow-data-loss
Verify an eligible pre-existing initial schemamigrate baseline --reason TEXT
Recover a nontransactional index migrationmigrate 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.

Type to search this version.