laravel-shift/factory-generator
Generate Laravel model factories automatically from your existing database schema. This Laravel Shift package inspects table columns and writes realistic Faker-based definitions, saving hours when adding tests or seed data to legacy applications.
laravel-shift/factory-generator is a dev-only codegen tool: it introspects your database schema and writes database/factories/*Factory.php files with Faker calls mapped to each column's type. Its value is highest in legacy/large-schema apps where hand-writing 40 factories is the reason tests never get written.
composer require laravel-shift/factory-generator --dev
Generate everything, or one model at a time:
php artisan generate:factories # all discovered models
php artisan generate:factories User # single model
(If the command name differs in your pinned version, php artisan list | grep generate will show it — the entry point is the same.)
Where to look first:
database/factories/UserFactory.php and read every Faker call — that output is the package's opinion about your schema.vendor/laravel-shift/factory-generator/src/, specifically the column-type→Faker mapping. When a generated value is wrong, the map is almost always why, and it's the thing you'll want to override.Best first use case: pick one mid-sized model with a messy table (foreign keys, nullable columns, an enum), generate just that factory, and diff it against a hand-written one. That single exercise tells you whether the output is 80% usable or 20% usable for your schema, which determines whether you adopt it wholesale or only for bootstrap.
v2.3 adds Laravel 13.x compatibility. If you're planning a Laravel 13 upgrade, this is the version that lets you keep the tool in the upgrade branch — but see the regeneration note in Gotchas.
Bootstrap-then-own. Treat generated factories as a first draft you commit and then edit, not as artifacts you regenerate continuously. The productive loop is: generate → review each file → extract anything hand-tuned into state methods → commit.
Generate against a representative schema. The generator reads the live database connection, so fidelity depends entirely on what's migrated. Run it against a database built from your real migrations (ideally the same driver as production), not a half-migrated local SQLite file.
Generate in dependency order for foreign keys. Foreign-key columns become Model::factory() references. If the parent factory doesn't exist yet, you get a broken reference. Either run the command twice (second pass picks up newly created parents), or generate parent models first.
Schema-change workflow. After a migration adds/renames columns, regenerate that one model and diff:
php artisan generate:factories Invoice
git diff database/factories/InvoiceFactory.php
Small, per-model diffs are reviewable. A full generate:factories run is not.
Split hand-written behaviour into states, not inline edits. Keep generated attribute arrays pristine-ish and add domain states below them:
public function overdue(): static
{
return $this->state(fn () => ['due_at' => now()->subWeek(), 'status' => InvoiceStatus::Overdue]);
}
States survive a regeneration diff far more readably than scattered edits inside definition().
Seeder + test integration. Generated factories are immediately usable for local dev seeding (Invoice::factory()->count(50)->create()) and for the first test in each model's suite. The realistic adoption path in a legacy app is: generate all factories, then write tests model by model, fixing each factory as you go — the factory gets correct exactly when a test needs it to be.
Post-process what can't be inferred. Enums, JSON shapes, money/currency pairs, and constrained foreign keys (role_id pointing at a fixed set of rows) have no schema signal. Plan a manual pass over those columns; don't expect the tool to guess them.
count(). Mapping a string column to $faker->word ignores unique indexes. Any ->count(n) on an email, uuid, or slug column will throw. Add ->unique() (or a sequence) manually — this is the single most common first failure.--force clobbers hand edits. Regeneration overwrites existing factories. Commit before regenerating, and prefer per-model regeneration over bulk once you've started customising.null for nullable columns, not a mix. If your tests care about both paths, add explicit states.created_at/updated_at are skipped and deleted_at is typically left null. Add a trashed() state if you test soft-delete behaviour, and use ->state(['created_at' => ...]) when you need backdated rows.enum, Postgres jsonb, and SQLite's loose typing (no native boolean) produce different mappings. If type fidelity matters, generate against the production driver; otherwise review boolean/date columns extra carefully on SQLite.composer dump-autoload first — the scanner relies on autoloading, and non-standard namespaces are a frequent cause of "it generated 12 of my 15 factories."require-dev. It's a schema-introspecting dev tool; nothing at runtime needs it, and you don't want its dependencies in a production image.^2.3 before moving an app to Laravel 13. Note that major Laravel upgrades change the schema-inspection API underneath the generator, so diff generated output after the upgrade rather than assuming identical results; type mappings can shift even when the package version is unchanged.Schema::getColumns('your_table') against the generator's type map. If the column type reported by the schema builder doesn't match what you expect, the bug is in your database, not the package.How can I help you explore Laravel packages today?