giacomomasseron/laravel-models-generator
Generate Eloquent models directly from an existing database with this Laravel artisan command. Supports MySQL, MariaDB, SQLite, PostgreSQL and SQLServer, plus polymorphic relations, UUID/ULID columns, enum, URI and JSON casting, and optional model factories.
Architecture fit
This is a dev-time code generation tool, not a runtime dependency. It ships one Artisan command (laravel-models-generator:generate) that introspects an existing schema and emits Eloquent models, and optionally factories, into app/Models. That shape is architecturally cheap: nothing enters the request lifecycle, no service provider touches production requests beyond command registration, and the emitted artifact is plain PHP owned by our repository. The tool is therefore disposable while its output is not — we can uninstall it at any time and keep every generated model. That property materially lowers the adoption threshold relative to a runtime library, and it should be the framing in any approval discussion.
Fits well for three scenarios: (1) brownfield adoption — a legacy MySQL/PostgreSQL database being wrapped in a Laravel service; (2) large schemas (100+ tables) where hand-writing $fillable, $casts, PHPDoc blocks, and inverse relationships is pure toil; (3) a schema-drift audit artifact. It fits poorly where models are already mature and hand-tuned, because generation is authoritative over the file, not additive.
The README signals a team that cares about output quality: PHPStan level 9/10-compliant generated code, Laravel 11/12/13 attribute style, enum/URI/JSON casts, UUID/ULID handling, polymorphic and pivot-aware relationships, plus config hooks for parent class, interfaces, traits, table-scoped traits, global scopes, observers, and query builders. For a package with 58 stars and zero dependents, that is a disproportionately strong feature surface, and it addresses the main gap left by the effectively unmaintained predecessors in this niche.
Integration feasibility
High. Installation is a single composer require --dev, a publishable config file, and a command with -c (connection), -s (schema), and -t (single table) scoping. The -t flag is the decisive feasibility lever: it allows a per-table, reversible pilot rather than a big-bang migration. Driver coverage (MySQL, MariaDB, PostgreSQL, SQLite, SQL Server) matches our likely footprint; anything outside that set is explicitly deferred to Doctrine DBAL and should be treated as unsupported today.
Technical risk
The dominant risk is destructive regeneration. clean_models_directory_before_generation defaults to true, so a re-run deletes the contents of the models path. Run against a directory containing hand-edited models, that is unrecoverable outside of git. The package's own mitigation is base_files mode (abstract Base classes regenerated, child classes extended and hand-maintained), and that mode should be considered mandatory for any table we intend to regenerate more than once.
The second risk is silent incorrectness in relationship inference. A wrong belongsTo or belongsToMany does not throw — it produces wrong query results later. Inference is convention-based, so we should expect misreads on composite keys (Eloquent cannot express them at all), non-standard pivot table names, legacy columns without foreign key constraints, and schemas where foreign keys are absent by design.
Third, the health profile: one maintainer, 58 stars, zero dependents on Packagist. Bus factor is one. This is acceptable precisely because the output is not coupled to the package, but it means no version upgrade should be taken blind and composer.lock pinning is non-negotiable.
Key questions
clean_models_directory_before_generation: false and a scratch output path, does regeneration produce a clean, deterministic git diff, or does ordering churn make it unreviewable?belongsToMany? What is the override path when both are needed?parent and register our audit traits via traits/table_traits?base_files mode actually preserve hand-edits across two consecutive generations — verified empirically, not from the README?Stack fit
Laravel 9–13 is squarely our range, and the config surface is designed for conformity rather than takeover: parent, namespace, path, interfaces, traits, table_traits, relationships_name_case_type, timestamps.fields, and table_prefix all let generated models slot into existing conventions (base model, tenancy, auditing, soft deletes) instead of fighting them. Teams running static analysis get compliant output rather than a baseline full of suppressions.
Migration path
Adopt as a dev dependency and a bootstrap/audit tool, not as a permanent code owner. Concretely: pin the exact version in composer.lock; publish the config; point the command at a read-only replica or a schema dump restored locally; set clean_models_directory_before_generation: false and a temporary output path before the first run. The first run's output is a review artifact, not a commit — it tells us how well the tool reads our schema and where inference fails. Then adopt per table with -t, and only enable base_files for tables we accept as regenerable.
Compatibility
Existing hand-written models should not be regenerated over. Generate into a separate namespace, diff, and merge manually, or restrict to tables that are still bare. The config's except, exclude_columns (with regex support), exclude_relationships, and exclude_factories lists need to be populated up front — particularly exclude_factories, which defaults to skipping users/jobs/job_batches/failed_jobs sensibly but will otherwise overwrite factory files that carry domain-specific state.
Sequencing
base_files idempotency across two runs on one sacrificial table.Maintenance Near-zero runtime maintenance: no production surface, no data path, no observability requirement. The real maintenance load is on the output — generated models become our code and our problem. Budget review time rather than engineering time. A 200-table schema can produce thousands of files and a PR no human can meaningfully review; batch by domain or schema.
Support Single maintainer with no downstream dependents means no community backstop and slow fixes for driver-specific bugs. Mitigate by pinning versions, treating the tool as replaceable, and keeping a one-page internal record of exactly which config options we rely on so a fork or hand-rolled replacement is a contained effort. Given the license and the nature of the output, the exit cost is genuinely low — that is the package's strongest operational argument.
Scaling
The tool scales fine to large schemas mechanically; the constraint is human — review throughput and the risk of a mass rewrite commit. Inversely, incremental -t adoption scales down to a single table, which is the right default for a large existing codebase.
Failure modes
Ramp-up
Low. One command, one config file, roughly half a day for a developer to be productive and one to two days for a team to establish conventions. The enablement work is not learning the tool but deciding policy up front: which tables are tool-owned vs. hand-owned, whether base_files is mandatory, what the relationship-inference review checklist is, and where the read-only database credentials come from.
Recommendation: adopt as a scoped dev-time bootstrap and audit tool with base_files enabled and destructive cleaning disabled; do not adopt as an ongoing owner of existing, hand-maintained models.
How can I help you explore Laravel packages today?