Skip to content

Migrations

Overview

Sutomo uses a custom migration runner (database/migrations/0000_runner_migration.php) instead of Laravel's default flat migration directory. Migrations are organized into versioned subdirectories (e.g., v1_0_0/, v1_1_0/) to keep the migration history manageable and provide clear versioning.


Version Structure

database/migrations/
├── 0000_runner_migration.php      # Custom runner (reads env config)
├── v1_0_0/                        # Initial schema
│   ├── 000_migrate_core.php
│   ├── 001_migrate_platform.php
│   ├── 002_migrate_recruitment.php
│   └── ... up to 017_*
├── v1_1_0/                        # Next feature batch
│   ├── 002_create_application_management_table.php
│   └── ...
├── v1_2_0/
├── v1_3_0/
├── v1_4_0/
└── v1_5_0/

Naming Convention

{version}/
└── {sequence}_{descriptive_snake_name}.php
PartRuleExample
{version}v{major}_{minor}_{patch}v1_3_0
{sequence}3-digit zero-padded number000, 001, 017
{name}Snake_case descriptioncreate_application_management_table

Sequence Rules

  • Start at 000 for each version directory
  • Increment by 1 for each new migration: 000, 001, 002, ...
  • Never use 999 — it breaks ordering and was previously renamed to 017
  • Custom ordering overrides exist in the runner for v1_0_0 if needed

How to Create a Migration

1. Determine the version

Check the latest version folder. If there is none for the current feature batch, create a new one:

bash
# If latest is v1_5_0 and you're adding a new feature:
mkdir database/migrations/v1_6_0

2. Find the next sequence number

bash
ls database/migrations/v1_5_0/
# 000_add_lat_lng_to_schools_table.php
# 001_add_username_to_users_table.php
# ... next is 007

3. Generate the migration

Use php artisan make:migration and then move it:

bash
php artisan make:migration add_phone_to_users_table
# Creates: database/migrations/2026_07_30_123456_add_phone_to_users_table.php

mv database/migrations/2026_07_30_123456_add_phone_to_users_table.php \
   database/migrations/v1_5_0/007_add_phone_to_users_table.php

4. (Optional) Register in runner

If your migration needs a custom execution order within its version folder, add it to sortMigrations() in the runner:

php
private function sortMigrations(string $folder, array $files): array
{
    $overrides = match ($folder) {
        'v1_0_0' => [
            '007_migrate_geographic.php' => 1,
            '003_migrate_academic.php' => 2,
            // ...
        ],
        default => [],
    };
    // ...
}

Runner Configuration

The runner reads environment variable MIGRATION_RUNNER_FOLDERS:

env
# Default (all versions)
MIGRATION_RUNNER_FOLDERS=v1_0_0,v1_1_0,v1_2_0,v1_3_0,v1_4_0,v1_5_0

# Tests override (phpunit.xml)
<env name="MIGRATION_RUNNER_FOLDERS" value="v1_0_0"/>

Rules:

  • Folders are executed in the order they appear in the comma-separated list
  • Missing folders are silently skipped
  • The runner outputs folder names during migration: --- Migrating: v1_0_0 ---

Migration Rules

Do ✅

  • Create a new version directory for each significant feature batch
  • Use descriptive names that explain what the migration does
  • Keep migrations small and focused — one table or one column change per file
  • Use Schema::hasTable() checks in later versions to avoid duplicates
  • Test both up() and down() methods

Don't ❌

  • Don't edit migrations that have already been deployed — create a new one
  • Don't use sequence numbers like 999 — they break ordering
  • Don't put unrelated schema changes in the same file
  • Don't delete old migrations from production — only from local/dev
  • Don't create migrations outside a version directory

Duplicate Table Prevention

When adding a migration in a later version that might overlap with an earlier version, always check:

php
if (! Schema::hasTable('academic_years')) {
    Schema::create('academic_years', function (Blueprint $table) {
        // ...
    });
}

Key Files

FilePurpose
database/migrations/0000_runner_migration.phpCustom runner — reads folders env, executes migrations in order
database/migrations/v1_0_0/ to v1_5_0/Versioned migration directories
phpunit.xmlMIGRATION_RUNNER_FOLDERS env for test environment
.envMIGRATION_RUNNER_FOLDERS env for local dev