Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Migration Generator Laravel Package

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.

Deep Wiki
Context7

Getting Started

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.

Implementation Patterns

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.

Gotchas and Tips

  • It is a snapshot, not history. You lose migration chronology, data backfills, and irreversible steps. Never run this over an existing app's migrations table and expect both sources of truth to coexist — pick one.
  • Driver fidelity varies. Enums, geometry types, generated/computed columns, partial and expression indexes, check constraints, and comments may not round-trip cleanly between MySQL, PostgreSQL, SQLite, and SQL Server. Always verify with a schema diff.
  • SQLite lies to you. migrate:fresh on SQLite can succeed where MySQL fails (index name lengths, unsigned integers, ON UPDATE). Test against the production engine.
  • Unsigned prefixes and index-name length. MySQL 5.7 vs 8.0 differ on index name limits and unsigned handling. The config typically exposes flags for unsigned prefixes and for preserving defined index/foreign-key/primary-key names — set these to match your target version explicitly.
  • Timestamp collisions. Generating many tables in one run can produce identical timestamps with suffixes. Check the generated filenames before running migrate; ordering bugs often show up here first.
  • Config caching. If you change config/migration-generator.php and see no effect, run php artisan config:clear.
  • Anonymous vs named migration classes. Anonymous class migrations require Laravel 9+. On older projects, verify the generator emits named classes or you'll get "cannot redeclare class" errors.
  • down() is usually just dropIfExists. That's fine for most tables, but review pivot tables and any table whose drop order matters.
  • Views, triggers, routines, and functions are out of scope. Handle them with raw SQL migrations, schema:dump, or deployment scripts.
  • Read-only means read-only. Introspection is safe, but the generation step writes files, and an accidental php artisan migrate is not safe. Run against a clone or a read replica, never production.
  • Dev-only dependency. Keep it in require-dev; CI jobs that need it should install with --dev. Don't let it leak into a production image.
  • Extension points. The config is the primary lever (paths, naming schemes, skip lists, sort behavior). If you need custom type mapping, the generator classes are ordinary PHP and can be extended or rebound in a service provider — worth doing only if post-processing proves insufficient.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource