bastinald/laravel-automatic-migrations
A Laravel package that automates database migrations, helping you generate and manage schema changes with less manual boilerplate. It streamlines keeping migrations and your application's database structure in sync.
composer require bastinald/laravel-automatic-migrations
Laravel 5.5+ package discovery should register the service provider automatically; if the command doesn't appear in php artisan list, add Bastinald\AutomaticMigrations\AutomaticMigrationsServiceProvider to config/app.php manually.
Where to look first. The package is small — read src/ top to bottom before writing any model code:
First use case — a throwaway model on a scratch database. Don't start on your real schema. Point DB_CONNECTION at SQLite (or a disposable MySQL database), create a Post model, declare its columns using whatever schema definition the README/trait expects, run the generator command, and open the file it drops into database/migrations/. Read the generated up() and down() line by line, then php artisan migrate. Because you're on a scratch DB you can migrate:fresh freely and iterate on the model definition until the generated SQL matches what you'd have written by hand. That loop — model → generate → read → fresh — is the entire workflow of the package, and you should understand it before it touches a schema you care about.
Model-first scaffolding for greenfield work. The package's real value is collapsing the "create model, create migration, keep the two in sync" ceremony into one place during the early, high-churn phase of a feature. Define the columns next to the $fillable/$casts they correspond to, generate, migrate, and move on. Once a table stabilises, stop regenerating it.
Generated migration as a first draft, not the source of truth. The healthy pattern is: generate → open the file → hand-edit in the constraints the generator can't infer (indexes, foreign keys, unique, precise decimal(10,2), enum choices) → commit → never regenerate that file again. Treat the generator as a scaffolding tool that gets you 70% of a migration in one keystroke, not as a declarative schema manager.
Schema diffing as a dev loop. For a table you're actively designing, keep the model definition authoritative only until the first commit. Change the model, regenerate into a fresh migration (or migrate:fresh locally), and eyeball the diff against the previous migration. This is fast for solo prototyping and dangerous the moment a teammate has run the old migration — which is why the next pattern matters.
Separate "generated" from "shipped". Adopt a hard rule: any migration that has been merged to main or run outside your machine is hand-maintained forever. New work gets generated migrations; existing work gets hand-written Schema::table(...) changes like any normal Laravel app. This is the single rule that keeps the package from becoming a liability.
Drift check in CI (optional but cheap). If you lean on the generator, add a CI step that regenerates into a temp directory and fails if the output differs from what's committed. It catches "someone edited the model but forgot the migration" without needing the package at runtime.
Pair with RefreshDatabase in tests. Generated migrations are ordinary migration files, so the normal test suite works unchanged. Just make sure your phpunit.xml uses an in-memory SQLite connection — you do not want a generator hook running during test bootstrap.
Baseline mature apps with schema:dump. On a large existing project, run php artisan schema:dump and let the package generate only the new tables going forward. Mixing auto-generated and legacy migrations from scratch is where you'll hit ordering problems.
The release date is the headline gotcha. Last release September 2021 — that's Laravel 8 era. Expect friction on Laravel 9/10/11: command signature changes, doctrine/dbal decoupling, and return-type declarations on Migration methods. Install it in a branch, run a full migrate:fresh --seed, and check the generated files compile before committing to the approach. With 45 stars and 0 dependents there is no community evidence that it works on your version — you are the QA.
Type inference is lossy by design. Anything the generator produces will be a guess: string lengths default to 255, decimals lose precision, nullable is often inferred from a leading ? or not at all, defaults are almost always missing, and indexes/foreign keys/composite uniques are essentially never generated. Read every generated column before running it and budget time for hand-editing. If the mapping file has a type table, that table is your contract — extend it rather than fixing output by hand every time.
down() methods are frequently naive. Auto-generated rollbacks often do the obvious dropIfExists, which is fine, but watch for tables that get dropped while foreign keys from elsewhere still reference them. On anything with relationships, review or rewrite the down().
Regeneration can clobber manual edits. If the command writes to an existing file or picks a colliding name, you'll silently lose hand-written constraints. Commit or stash before running the generator, and diff before you accept anything. Never run it with a dirty working tree on a schema you care about.
Naming and ordering collisions. Two models targeting the same table, or generated migrations timestamped into the middle of an existing dependency chain, will produce confusing failures. Keep generated migrations at the end of the timeline and check php artisan migrate --pretend when ordering looks suspicious.
Dialect drift. SQLite will happily accept things MySQL rejects and vice versa. Generate and review against the database engine you actually deploy on, not just your local SQLite file — especially for unsigned, json, and enum-ish columns.
Never point it at production. This is a development-time scaffolding tool. It belongs in require-dev unless you're certain nothing in it hooks into normal application boot, and the generate command should never be part of a deploy script.
Debugging recipe. php artisan migrate --pretend to see the SQL without executing; dump the generated migration file directly rather than trusting the console output; Schema::getColumnListing('table') before and after to confirm what actually landed. If the command silently does nothing, the service provider likely isn't registered or the model isn't using the trait.
Extension points, in order of preference. Publishable stubs (if present) → subclassing the generator and overriding the type map → forking. With this star count and last-release date, forking is a legitimate and probably expected outcome; the codebase is small enough that reading and vendoring it is faster than fighting version constraints.
How can I help you explore Laravel packages today?