laravel-migration-generator builds migrations from a live database
Generate migrations from existing database structures
At a glance
- What is it?
- This package reads an existing database and writes Laravel migration files that describe it, which is the answer for projects stuck with doctrine/dbal change() calls that SQLite cannot run and for projects that have a database but no migrations at all. Its behaviour is driven by a long list of environment variables, including per-driver overrides for MySQL, SQLite, PostgreSQL and SQL Server.
- Who is it for?
- laravel-migration-generator fits a Laravel or Lumen project that needs migration files describing a database it already has, especially a SQLite test suite that cannot replay doctrine/dbal change() migrations, and it does not fit a project that wants its migration history reconstructed, since the output reflects the current schema rather than the sequence that produced it.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 44 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Migrations reconstructed from the current schema, not from history
The package does one thing: it looks at a database that already exists and writes Laravel migration files that describe that structure. The README calls it an alternative to the schema dump provided by Laravel, and the difference in direction is the whole point. A schema dump captures the end state as data to be loaded. This package captures the end state as code that can be replayed.
That direction has consequences. The generated files describe tables, views and indexes as they exist right now, which is exactly what you want when the schema drifted away from what your migration files claim, and exactly what you cannot use if you need to know how the schema got that way. The migrations it writes are create-table migrations with a timestamp prefix, and the naming is configurable.
Two use cases are named in the README. The first is a project with many migrations that alter tables using ->change() from doctrine/dbal, which SQLite does not support, where you need a way to get table structures updated for SQLite to use in tests. The second is a project that has a database and no migrations, which you want to turn into base migrations. The second case is the cleanest fit: there is no ambiguity about what the schema is because there is only one state of it.
The default output location says which of the two cases the author had in mind. By default the files are created in tests/database/migrations.
The doctrine/dbal and SQLite problem is the design driver
Understanding why this package exists requires knowing the Laravel and SQLite friction it works around.
A Laravel application that alters a column typically writes a migration calling ->change() on the column definition, and that method depends on doctrine/dbal to work out the difference between the old and new column states. SQLite does not support that approach, because SQLite's alter table support is limited and doctrine/dbal cannot work out a column change there. The consequence for a test suite is direct: the migrations that run fine against MySQL or PostgreSQL cannot run against an in-memory or file SQLite database.
The workaround this package offers is to skip the replay entirely for tests. You keep the original migrations for your production database, and you generate a set of create-table migrations that reproduce the current structure in a form SQLite can execute. The generated files live under tests/database/migrations by default, which is why that path is the default and why the README frames the tool as a way to get table structures updated for SQLite to use in tests.
Two cautions follow from that framing. The generated migrations reflect the schema as it is at generation time, so any drift between your migration files and the database becomes invisible in the generated output. And the generated file names follow a create-table naming scheme, so they will not slot into an existing chronological migration sequence without renaming.
Installing the package and publishing its assets
Installation is a Composer require plus, optionally, publishing the vendor files so you can customise the stubs.
composer require --dev bennett-treptow/laravel-migration-generatorPublishing the package assets is a separate step, done with the standard Artisan vendor publish command:
php artisan vendor:publish --provider="LaravelMigrationGenerator\LaravelMigrationGeneratorProvider"That publish step matters beyond cosmetics. The README says you need the vendor assets published if you want to customise the migration stubs, and the repository has a stubs directory alongside config, docs, src and tests, with a CHANGELOG.md and an UPGRADE.md that are worth reading when upgrading across major versions.
Lumen needs a different route. The Composer require is the same, but there is no vendor:publish step to rely on, so the instructions are to copy the config file from vendor/bennett-treptow/laravel-migration-generator/config into your Lumen config folder and register the service provider in bootstrap/app.php:
$app->register(\LaravelMigrationGenerator\LaravelMigrationGeneratorProvider::class); The package is a development dependency by design, since the migrations it produces are usually an artefact of your development or CI workflow rather than something you ship to production.
The composer.json file and the pint.json style configuration in the repository root suggest the package follows Laravel's own conventions, and phpunit.xml means the package ships its own tests.
One Artisan command with three options that matter
Generation happens through a single Artisan command:
php artisan generate:migrationsThe README tells you to run it whenever you have database changes or when you are ready to squash your database structure down to migrations, which makes it usable both as a periodic sync and as a one-off squash.
Three options control the run. The --path option chooses where the files are written, and the default is tests/database/migrations, so pointing the command at your real migration directory takes an explicit argument:
php artisan generate:migrations --path=database/migrationsThe --connection option selects the database connection to read from, which matters when an application defines more than one:
php artisan generate:migrations --connection=mysql2The --empty-path option clears the output directory before writing, which is the option you want when regenerating rather than merging:
php artisan generate:migrations --empty-pathNote the naming collision risk. Since the default output path sits inside the tests directory while the package also has LMG_SKIPPABLE_TABLES defaulting to migrations, the intention is clearly that your own migration bookkeeping tables are left out of the generated output, but you should check what your generated set actually contains before committing it.
Auto-running after migrations is limited to the local environment
The package can run itself. Setting the LMG_RUN_AFTER_MIGRATIONS environment variable to true makes the command fire after your migrations complete, latching into the MigrationsEnded event and running with the default options taken from your environment variables.
The restriction is the interesting part. The README states that it will only run when your app environment is set to local. That is a sensible guard, because the generated output reflects whatever schema the migrations just produced, and on a shared or production environment that would be noise at best. It also means the automatic mode is a development convenience, not something you can rely on in CI where the environment is usually something like testing.
The companion variable LMG_CLEAR_OUTPUT_PATH does the same thing as passing --empty-path on the command, so the two mechanisms cover the same ground: environment variables for unattended runs, command options for one-off runs you are watching.
For teams that want the generated set to stay in step with the migrations automatically, this pairing is the interesting part of the package, because it removes the manual step of remembering to regenerate after every schema change.
The configuration surface is wide, and per-driver overrides are the sharp edge
The configuration table is the largest part of the README, and it explains most of the package's behaviour. Four variables decide where files go and what they are called: LMG_OUTPUT_PATH, LMG_TABLE_NAMING_SCHEME with the default [Timestamp]_create_[TableName]_table.php, LMG_VIEW_NAMING_SCHEME, and the output path default of tests/database/migrations.
Two variables decide what is left out: LMG_SKIPPABLE_TABLES, a comma delimited list defaulting to migrations, and LMG_SKIP_VIEWS plus LMG_SKIPPABLE_VIEWS for views.
Then come the fidelity switches, and these are where the generator can surprise you. LMG_PREFER_UNSIGNED_PREFIX makes it use unsigned variant methods instead of the ->unsigned() modifier. Four separate variables control index naming: LMG_USE_DEFINED_INDEX_NAMES, LMG_USE_DEFINED_FOREIGN_KEY_INDEX_NAMES, LMG_USE_DEFINED_UNIQUE_KEY_INDEX_NAMES and LMG_USE_DEFINED_PRIMARY_KEY_INDEX_NAMES, each defaulting to true and each making the generated file use the name the database already has. LMG_WITH_COMMENTS exports comments with the ->comment() method. LMG_USE_DEFINED_DATATYPE_ON_TIMESTAMP is false by default, which means the generator uses ->timestamps() by mashing up created_at and updated_at regardless of the datatype the database defines, and switching it to true changes that behaviour.
The sharp edge is that most of these have a per-driver override. LMG_MYSQL_TABLE_NAMING_SCHEME, LMG_SQLITE_OUTPUT_PATH, LMG_PGSQL_SKIPPABLE_VIEWS and the matching SQL Server variables all default to null, and when set they override the general setting for that driver. So you can end up with a MySQL naming scheme in production and a different one in tests without any file to explain why.
One entry looks incomplete: LMG_SORT_MODE defaults to foreign_key, and the options column lists only foreign_key. The sorting of generated output is therefore effectively fixed in the documented surface, and you should not expect other sort orders without checking the source.
Where this is the wrong tool for the job
There are clear cases where generating migrations from a live database is the wrong approach.
The first is when the history matters. If your production database was built by a long sequence of migrations and you need those steps preserved for an audit, a rollback plan or a re-run against a fresh database, a description of the current schema does not reconstruct that sequence. The generated files describe the destination, and the history is simply gone.
The second is when the database is the wrong source of truth. A generator can only describe what the database currently looks like, so if the database has drifted because someone applied a change by hand, the generated migrations will faithfully encode the drift and make it permanent. The tool treats the database as authoritative, which is right for the squash use case and wrong for the drift case.
The third is the doctrine/dbal situation, seen from the other side. If your project never uses ->change() and your test database can run the same migrations as production, this package adds a second source of truth for no gain. The README's own first use case is about working around a specific limitation, so the honest scope is narrow.
There is also the matter of what the generated code does not capture. The README documents naming, indexing, comments and timestamp handling, and it does cover views, through the view naming scheme and skip options, but it does not document whether triggers, stored procedures, foreign key enforcement settings or the precise collation of each column are reproduced. Assume they need checking on a first run, especially the driver-specific overrides, which is easier to verify on a scratch database than to discover later in a test run.
Editorial conclusion
laravel-migration-generator fits a Laravel or Lumen project that needs migration files describing a database it already has, especially a SQLite test suite that cannot replay doctrine/dbal change() migrations, and it does not fit a project that wants its migration history reconstructed, since the output reflects the current schema rather than the sequence that produced it. Before running it, confirm that the target connection points at the database you intend to read, decide whether the generated files should land in tests/database/migrations or database/migrations, and review LMG_SKIPPABLE_TABLES so the migrations table itself is not emitted. The last push was on 2026-09-09, shipped as release 4.6.0.
Frequently asked questions
How do I generate Laravel migrations from an existing database?
Install the package with composer require --dev bennett-treptow/laravel-migration-generator, publish the vendor assets if you want custom stubs, then run php artisan generate:migrations. By default the files are written to tests/database/migrations.
Can I run the generator against a specific database connection?
Yes. The --connection option selects the connection to read from, for example php artisan generate:migrations --connection=mysql2, which is useful when an application defines more than one database connection.
What problem does laravel-migration-generator solve with SQLite?
The README describes it as a way to get table structures updated for SQLite to use in tests, for projects whose migrations alter tables with the ->change() method from doctrine/dbal, which SQLite does not support. The generator writes create-table migrations that SQLite can execute.
How do I configure the migration file names and output location?
LMG_OUTPUT_PATH sets the output path relative to the project root and defaults to tests/database/migrations, LMG_TABLE_NAMING_SCHEME sets the table file name pattern with a default of [Timestamp]_create_[TableName]_table.php, and LMG_VIEW_NAMING_SCHEME does the same for views. Per-driver variables such as LMG_MYSQL_TABLE_NAMING_SCHEME and LMG_SQLITE_OUTPUT_PATH override the general settings when they are not null.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/bennett-treptow-laravel-migration-generator)Was this useful?