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.phpwill be ignored;2024_02_16_000001_create_users_table.phpwill be processed. - Incorrect directory: The file must reside in
database/migrationsor 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
migrationstable, Laravel considers it complete. Usephp artisan migrate:rollbackor 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-autoloadhas 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
migrationsdatabase table to determine which migrations are pending. - Autoloading coordination via
composer dump-autoloadensures 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →