fr3on / laravel-forecast
Preview pending migration impact — row counts, lock estimates, and risk ratings — before you run migrate.
0.0.1
2026-04-10 13:21 UTC
Requires
- php: ^8.2
- illuminate/console: ^10.0|^11.0|^12.0|^13.0
- illuminate/database: ^10.0|^11.0|^12.0|^13.0
- illuminate/filesystem: ^10.0|^11.0|^12.0|^13.0
- illuminate/support: ^10.0|^11.0|^12.0|^13.0
Requires (Dev)
- laravel/pint: ^1.0
- orchestra/testbench: ^8.0|^9.0|^10.0
- pestphp/pest: ^2.0|^3.0
README
php artisan migrate:forecast— see exactly what your pending migrations will do, how many rows are at risk, and how long the table lock might last, before you typemigrate.
The problem
migrate --pretend gives you raw SQL. The confirmation prompt gives you nothing. Neither tells you:
- "This ALTER TABLE touches a 12M-row table — expect ~8 minutes of locking"
- "This DROP COLUMN still has data in 4,200 rows"
- "This NOT NULL column has no DEFAULT — it will fail on existing rows"
Teams find this out the hard way, mid-deploy, at 2am.
Installation
composer require fr3on/laravel-forecast
The service provider is auto-discovered. No configuration is required to start.
Optionally publish the config:
php artisan vendor:publish --tag=forecast-config
Usage
php artisan migrate:forecast
Example output:
Laravel Forecast | 3 pending migrations
2024_08_01_add_status_to_orders
┌──────────────────────────────────────┬─────────┬──────────┬──────────────────┐
│ Operation │ Risk │ Rows │ Est. lock │
├──────────────────────────────────────┼─────────┼──────────┼──────────────────┤
│ ADD COLUMN orders │ SAFE │ 4.2M │ < 1s (online) │
└──────────────────────────────────────┴─────────┴──────────┴──────────────────┘
2024_08_02_drop_legacy_payments_table
┌──────────────────────────────────────┬─────────┬──────────┬──────────────────┐
│ Operation │ Risk │ Rows │ Est. lock │
├──────────────────────────────────────┼─────────┼──────────┼──────────────────┤
│ DROP TABLE legacy_payments │ DANGER │ 38,441 │ instant │
└──────────────────────────────────────┴─────────┴──────────┴──────────────────┘
⚠ Entire table and all its data will be permanently deleted.
⚠ 38,441 rows will be permanently deleted.
2024_08_03_index_orders_user_id
┌──────────────────────────────────────┬─────────┬──────────┬──────────────────┐
│ Operation │ Risk │ Rows │ Est. lock │
├──────────────────────────────────────┼─────────┼──────────┼──────────────────┤
│ CREATE INDEX orders │ CAUTION │ 4.2M │ ~42s (estimated) │
└──────────────────────────────────────┴─────────┴──────────┴──────────────────┘
ℹ May lock the table during index creation on older engines.
Consider ALGORITHM=INPLACE, LOCK=NONE for zero-downtime.
SAFE: 1 CAUTION: 1 DANGER: 1
Run with --ci to exit code 1 on any DANGER operation.
CI / CD integration
php artisan migrate:forecast --ci
# exits 1 if any DANGER operation is detected — blocks the pipeline automatically
How it works
- Collects pending migrations — reads the migrations repository to find which files haven't been run yet.
- Captures SQL without executing — uses Laravel's built-in
connection->pretend()to get the exact SQL each migration would run. - Classifies each statement — regex-based SQL analysis extracts the operation type and table name.
- Queries row counts — runs
SELECT COUNT(*) FROM <table>against your live database. - Estimates lock time — applies heuristics based on operation type and row count.
No AST parsing. No reflection hacks. Just SQL string analysis + a COUNT query.
Risk classification
| Operation | Risk | Reason |
|---|---|---|
CREATE TABLE, ADD COLUMN with DEFAULT or nullable |
SAFE | Additive; online DDL on MySQL 8+ |
ADD COLUMN NOT NULL without DEFAULT |
DANGER | Will fail on non-empty tables |
DROP TABLE, DROP COLUMN |
DANGER | Irreversible data loss |
CREATE INDEX |
CAUTION | May lock table depending on engine version |
RENAME COLUMN / RENAME TABLE |
CAUTION | May break queries and views |
ALTER COLUMN (type/constraint change) |
CAUTION | Risk of data truncation |
NOT NULL constraint on existing column |
DANGER | Fails if any row contains NULL |
Configuration
After publishing config/forecast.php you can tune:
return [ // Row count above which extra warnings are shown 'large_table_threshold' => env('FORECAST_LARGE_TABLE_THRESHOLD', 1_000_000), 'medium_table_threshold' => env('FORECAST_MEDIUM_TABLE_THRESHOLD', 100_000), // Lock-time heuristics (milliseconds per 1,000 rows) 'ms_per_thousand_rows' => [ 'drop_column' => 10, 'create_index' => 10, 'alter_column' => 15, 'add_column' => 5, ], // Extra migration paths to scan (in addition to database/migrations) 'migration_paths' => [], ];
What it is NOT
- Not a replacement for
migrate— it only informs before you commit. - Not
migrate --pretend— that shows SQL; this shows impact. - Not
enlightn— that checks code security; this checks schema risk. - No SaaS, no agents, no database tables. Install and run immediately.
License
MIT