Migrations

Migrations help create your database and track how it evolves overtime. Here, we use GoMigrate to achieve this. Some added complexity is added to enable easy extendability and generate better logs throughout your development process.

Migrations go under pkg/db/migrations/<myNewMigration>.go. Its implemention uses Go's init() function, which means they're added to the list in alphabetical order. They migrate in that order (top to bottom) and rollback in the reverse order (bottom up). For this, it is best to maintain the naming convention of YYYYMMDD[00-99]_migration_description.

Here's a sample migration to get you started:

func init() {
	m := &gormigrate.Migration{}

	m.ID = "2022081801_create_cats_table"

	m.Migrate = func(db *gorm.DB) error {
		type Cat struct {
			models.ModelBase
			Name string `gorm:"size:255"`
			Type string `gorm:"size:255"`
		}

		return AutoMigrateAndLog(db, &Cat{}, m.ID)
	}

	m.Rollback = func(db *gorm.DB) error {
		if err := db.Migrator().DropTable("cats"); err != nil {
			logFail(m.ID, err, true)
		}
		logSuccess(m.ID, true)
		return nil
	}

	AddMigration(m)
}

The variable m holds the migration details and is added to the list of migrations at the end. m.ID is the identifier used by gomigrate to keep track of the migrations that already ran. So, make sure to change that for every migration.

Every migration has 2 methods to be implemented, the Migrate() and Rollback() method as described above. Make sure you use the logSuccess, logFail and AutoMigrateAndLog() functions to print the migrations that ran. This will come in very handy for remote deployments.

It's recommended to declare your models within each migration (separately from the models package) to keep track of the database schema change through time. You can add or delete columns, rename columns, and execute raw SQL in migrations.

Was this page helpful?

Consider supporting my work if you find it useful

Buy me a coffee