bennett-treptow/laravel-migration-generator
Laravel Migration Generator reverse-engineers an existing database into Laravel migration files. Point it at MySQL, PostgreSQL, SQLite, or SQL Server and get clean, ready-to-edit migrations—handy for legacy apps, audits, or bootstrapping new projects from an existing schema.
Install it as a dev-only dependency; it has no runtime role in production:
composer require --dev bennett-treptow/laravel-migration-generator
Laravel auto-discovers the service provider. Optionally publish the config so you can tune output naming, paths, and database-specific behavior:
php artisan vendor:publish --tag=migration-generator-config
# or, if the tag differs in your version:
php artisan vendor:publish --provider="BennettTreptow\LaravelMigrationGenerator\LaravelMigrationGeneratorServiceProvider"
The entry point is the generate:migrations Artisan command (confirm the exact signature and options with php artisan list / php artisan help generate:migrations for your installed version):
php artisan generate:migrations --tables=users
First use case: point it at a single, well-understood table and inspect the generated file before committing to a full run. The typical first real job is reverse-engineering a legacy or undocumented database into a Laravel baseline, or generating migrations for a test fixture schema. Look first at three things: the published config/migration-generator.php, a single generated file under database/migrations (or your configured path), and the package README for driver-specific caveats.
Generate into a scratch directory or a branch, not on top of your hand-written migrations. The safest first loop is: generate one table → run php artisan migrate:fresh on a throwaway database → compare the resulting schema to the source → repeat.
Isolate the source connection. Add a read-only legacy connection in config/database.php, drive it from .env, and pass --connection=legacy. This keeps introspection credentials out of your app's default connection and makes it obvious the package is reading a foreign schema.
Per-table generation for reviewability. Use --tables=users,posts,orders for targeted regeneration and --ignore= to skip noise such as telescope_*, failed_jobs, cache, and migrations. Per-table output produces reviewable PRs and lets you evolve tables independently; use squash mode (--squash, if available in your version) only for a one-shot baseline snapshot of a whole database.
Generate to a dedicated path, then curate. --path=database/migrations/generated (or the config equivalent) keeps generated files separate from authored ones. Review, normalize, then move into the main migrations directory deliberately. This also makes it trivial to regenerate and diff.
Round-trip verification is the workflow. After generation, run php artisan migrate:fresh against the same engine and version as the source. Then diff the schema — mysqldump --no-data, pg_dump --schema-only, or Laravel's schema:dump — against the source. Anything that differs is either a package limitation or a genuine schema feature you need to handle manually. Treat this diff as the acceptance test.
Ordering and dependencies. Foreign keys mean generation order matters. The package sorts by dependency in most configurations, but verify that migrate:fresh succeeds on an empty database; if it fails, rename timestamps or hand-order the foreign key migrations.
Use it alongside schema:dump, not instead of it. For large production schemas, php artisan schema:dump gives you a fast baseline. Generated migrations are more useful when you intend to edit the schema afterward, when you need a reviewable history, or when you're porting to a new project. They are not a substitute for data seeding, backfills, triggers, or stored procedures.
CI drift check. Keep a reference SQL dump in the repo, generate migrations from it in a CI job, and diff against the checked-in baseline. This catches accidental schema drift and validates the package's output after upgrades.
Post-process rather than fight the generator. A short script that normalizes index names, strips driver-specific artifacts, and enforces your team's down() conventions is usually cheaper than customizing the package.
migrations table and expect both sources of truth to coexist — pick one.migrate:fresh on SQLite can succeed where MySQL fails (index name lengths, unsigned integers, ON UPDATE). Test against the production engine.migrate; ordering bugs often show up here first.config/migration-generator.php and see no effect, run php artisan config:clear.down() is usually just dropIfExists. That's fine for most tables, but review pivot tables and any table whose drop order matters.schema:dump, or deployment scripts.php artisan migrate is not safe. Run against a clone or a read replica, never production.require-dev; CI jobs that need it should install with --dev. Don't let it leak into a production image.How can I help you explore Laravel packages today?