How to Ensure the Laravel Migrate Command Detects and Applies New Migrations

The Laravel migrate command discovers new migration files by scanning timestamp-prefixed PHP files in the database/migrations directory (or custom paths specified via --path), comparing them against the migrations table, and executing only those not yet recorded.

When working with the laravel/framework repository, understanding how the migration discovery chain operates ensures that every new schema change you create is properly recognized and executed. The system relies on a specific set of conventions for file naming, directory structure, and autoloading coordination to determine which migrations are pending.

How Laravel Migration Discovery Works

The php artisan migrate command delegates file discovery to a series of interconnected classes within the Illuminate\Database namespace. Understanding this pipeline helps diagnose why a migration might be skipped.

Step 1: Defining Migration Paths via BaseCommand

The entry point for path resolution is BaseCommand::getMigrationPaths(), located in src/Illuminate/Database/Console/Migrations/BaseCommand.php. This method returns the default database/migrations directory merged with any additional paths supplied via the --path option.

// From BaseCommand.php (lines 15-31)
protected function getMigrationPaths()
{
    // Default path plus any --path arguments
    return array_merge(
        [$this->getMigrationPath()],
        $this->option('path') ?: []
    );
}

Step 2: File Naming Conventions and Sorting

Once paths are resolved, the Migrator::getMigrationFiles() method scans these directories for PHP files. Laravel strictly requires that migration filenames begin with a timestamp in the format YYYY_MM_DD_HHMMSS. This prefix ensures deterministic ordering when the Migrator sorts the file list alphabetically before execution.

For example, 2024_02_16_000001_create_posts_table.php is valid, while create_posts_table.php will be ignored by the scanner.

Step 3: Comparing Against the Migration Repository

The MigrateCommand (in src/Illuminate/Database/Console/Migrations/MigrateCommand.php) initializes the Migrator and calls run() with the discovered paths. Inside Migrator::run(), the system compares the sorted filenames against records in the migrations table. Only files whose names do not appear in this table are considered "pending" and are subsequently executed.

// Conceptual flow in MigrateCommand.php (lines 14-20)
$this->migrator->run($this->getMigrationPaths(), [
    'pretend' => $this->option('pretend'),
    'step' => $this->option('step'),
]);

Step 4: Autoloading and Class Resolution

After a migration is created using make:migration, the MigrateMakeCommand (in src/Illuminate/Database/Console/Migrations/MigrateMakeCommand.php) ensures the new class is discoverable. While the framework handles autoloading automatically in most cases, the class map may need refreshing if the migration class cannot be found. This is typically handled by running composer dump-autoload if you encounter autoloading errors.

Practical Implementation: Ensuring Migrations Are Detected

Follow these concrete steps to guarantee the laravel migrate command recognizes your new schema files.

Creating a Migration in the Default Location

Use the Artisan command to generate properly timestamped files:

php artisan make:migration create_posts_table --create=posts

This creates a file like 2024_02_16_000001_create_posts_table.php in database/migrations/, which will be automatically detected on the next migrate run.

Using Custom Migration Directories

For modular applications or packages, specify a custom path during creation:

php artisan make:migration add_status_to_orders --table=orders --path=custom/migrations

Then run the migrate command with the corresponding path option:

php artisan migrate --path=custom/migrations

Verifying Detected Migrations

Before running migrations, verify which files the system recognizes using the status command:

php artisan migrate:status

This outputs a table showing all migrations found in the scanned paths and whether they have been executed (indicated by a "Y" or "N" in the "Ran?" column).

Refreshing the Autoloader (When Needed)

If you manually copy migration files into the directory without using make:migration, or if you encounter "Class not found" errors, refresh the autoloader:

composer dump-autoload
php artisan migrate

Troubleshooting: Why the Laravel Migrate Command Might Skip Files

If your migration is not being applied, check these common causes:

  • Missing timestamp prefix: Files must start with YYYY_MM_DD_HHMMSS. create_users_table.php will be ignored; 2024_02_16_000001_create_users_table.php will be processed.
  • Incorrect directory: The file must reside in database/migrations or a path explicitly added via --path. Typos in directory names are a frequent cause of "migration not found" issues.
  • Already executed: If the filename exists in the migrations table, Laravel considers it complete. Use php artisan migrate:rollback or manually remove the entry from the database only if you are certain the migration was not fully applied.
  • Autoloading issues: If the class cannot be instantiated, ensure composer dump-autoload has been run, especially after manually copying files.

Key Source Files in the Migration System

Understanding these core files in the laravel/framework repository clarifies how the discovery mechanism operates:

File Role in Migration Discovery
src/Illuminate/Database/Console/Migrations/BaseCommand.php Defines getMigrationPaths(), which resolves the default database/migrations directory and merges custom --path arguments.
src/Illuminate/Database/Console/Migrations/MigrateCommand.php Entry point for php artisan migrate; initializes the Migrator and passes resolved paths to run().
src/Illuminate/Database/Console/Migrations/MigrateMakeCommand.php Handles make:migration; ensures files are created with proper timestamp prefixes and triggers autoloading updates.
src/Illuminate/Database/Migrations/Migrator.php Core engine that scans paths via getMigrationFiles(), compares filenames against the migrations table, and executes pending migrations.

Summary

  • The laravel migrate command discovers files by scanning timestamp-prefixed PHP files in database/migrations (or custom paths specified with --path).
  • File naming is critical: Only files matching the YYYY_MM_DD_HHMMSS_* pattern are recognized and sorted for execution.
  • The system compares discovered filenames against the migrations database table to determine which migrations are pending.
  • Autoloading coordination via composer dump-autoload ensures migration classes are discoverable, particularly when files are manually added.

Frequently Asked Questions

Why isn't my new migration being picked up by php artisan migrate?

The most common reason is a missing or incorrect timestamp prefix in the filename. Laravel requires the format YYYY_MM_DD_HHMMSS_description.php (e.g., 2024_02_16_000001_create_users_table.php). Files without this prefix are ignored by the Migrator::getMigrationFiles() scanner. Additionally, verify the file resides in database/migrations or a directory explicitly included via the --path option.

Can I store migrations in multiple directories?

Yes. While Laravel defaults to database/migrations, you can organize migrations in subdirectories or external package directories. When running migrations, use the --path option to specify additional locations: php artisan migrate --path=database/migrations/tenant --path=vendor/package/migrations. The BaseCommand::getMigrationPaths() method merges these custom paths with the default directory before scanning begins.

How does Laravel determine the order of migration execution?

Laravel sorts migration files alphabetically by filename, which is why the timestamp prefix is essential. When Migrator::getMigrationFiles() retrieves the list of files from the resolved paths, it performs a standard alphabetical sort. This ensures that 2024_01_01_000000_create_users.php executes before 2024_01_02_000000_create_posts.php, maintaining a chronological schema history regardless of when the files were physically created on disk.

Do I need to run composer dump-autoload after creating a migration?

Usually no. When you use php artisan make:migration, the MigrateMakeCommand automatically handles the necessary setup to ensure the new class is discoverable. However, if you manually copy a migration file into the directory without using the Artisan command, or if you encounter a "Class not found" error when running migrations, you should execute composer dump-autoload to refresh the autoloader class map before retrying php artisan migrate.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →