Skip to main content
Platforma provides a built-in migration system that allows you to version control your database schema changes using SQL files with special markers.

Overview

The migration system is built into the database.Database type and automatically discovers migrations from registered repositories. Migrations are executed in order based on their filenames, and the system tracks which migrations have been applied.

Migration File Format

Migration files use special comment markers to define up and down migrations:

Migration Markers

  • -- +migrate Up: Required marker that indicates the beginning of the forward migration
  • -- +migrate Down: Optional marker for rollback SQL (placed after the Up section)
  • -- +migrate ID: <custom_id>: Optional ID override (must be the first marker if used)

Migration ID

By default, the migration ID is derived from the filename without the .sql extension. For example, 1770095236_init.sql has an ID of 1770095236_init. You can override this by adding an ID marker as the first line:

Embedding Migrations

Use Go’s embed package to bundle migration files with your repository:
The Migrations() method must return an fs.FS containing your SQL files. Place your migration files in a migrations/ subdirectory next to your repository code.

Registering Repositories

Register your repository with the database to enable automatic migration discovery:
The RegisterRepository method automatically detects if your repository implements the migrator interface (has a Migrations() method) and registers it for migration.

Running Migrations

Run all pending migrations with the Migrate method:
The migration system:
  1. Creates a migrations tracking table if it doesn’t exist
  2. Reads all migration logs to determine which migrations have been applied
  3. Collects migrations from all registered repositories
  4. Applies pending migrations in lexicographic order by filename
  5. Records successfully applied migrations

Best Practices

Name migration files with a timestamp prefix to ensure correct ordering:
Use IF NOT EXISTS and IF EXISTS clauses to make migrations safe to re-run:
Always provide a Down migration and test that it correctly reverses the Up migration. This ensures you can roll back changes if needed.
Keep migrations focused on a single logical change to make them easier to understand and roll back if necessary.

Example: Complete Migration Setup

1

Create migration directory

Create a migrations/ directory in your repository package:
2

Write migration file

Create a migration file with timestamp prefix:
myrepo/migrations/1770095236_init.sql
3

Embed migrations in repository

Add the embed directive and Migrations method:
myrepo/repository.go
4

Register and migrate

Register the repository and run migrations:

Migration Tracking

The system tracks applied migrations in a migrations table with columns:
  • repository: The name used when calling RegisterRepository
  • id: The migration ID (filename without extension or custom ID)
  • timestamp: When the migration was applied
This ensures migrations are only applied once per repository.