laravel/legacy-factories
Provides support for the previous generation of Laravel factories (7.x and earlier) on Laravel 8.x and above, letting existing factory code keep working after upgrading.
Install the package as a development dependency—it belongs in require-dev, not production requires:
composer require laravel/legacy-factories --dev
On Laravel 5.5+ (and every version this package targets), the service provider is auto-discovered. There is nothing to register in config/app.php unless you are running a package test harness (see Testbench note below).
Where to look first: your database/factories/ directory. In legacy projects this is typically a single ModelFactory.php (or a handful of files) using the $factory->define(Model::class, fn () => [...]) closure syntax. If those files still exist and were not deleted during your Laravel 8+ upgrade, this package is all that stands between you and a green test suite.
First use case: get an upgraded application's tests passing without touching a single factory. After installing, verify the helper is back:
php artisan optimize:clear
php artisan tinker
>>> factory(App\Models\User::class)->create();
If that returns a persisted User, run the suite. The package's entire value proposition is that you can defer factory refactoring until after the upgrade lands.
factory(User::class, 10)->create() in tests and seeders work unchanged. Treat the package as a bridge, not a destination.$factory->define() and new UserFactory extends Factory classes. Adopt class-based factories only for new models or factories you are actively touching. Do not attempt to share definitions between the two systems—they are independent.factory(User::class)->create(['role' => 'admin']), .states(['active']), .times(3), .raw(), .make(), and ->create() all behave as in Laravel ≤7. Custom state closures registered with $factory->state(Model::class, 'admin', fn () => [...]) still resolve.factory(Relation::class)->create()->id calls inside a define() closure continue to work. This is often the trickiest part to migrate, so leave relational models on legacy factories longer than simple ones.factory(Model::class, 20)->create() for fixture generation need no changes. This is usually where you should start your migration—seeders are easy to validate in isolation with php artisan db:seed --class=....$factory->define() block, (4) run the suite. Do not delete a legacy definition until every call site is migrated—mixed use of the same model across both APIs will produce confusing state differences.php artisan test works but a package's Testbench suite renders factory() undefined, register the provider explicitly in getPackageProviders() or createApplication().factory() helper and closure registration. It does not let the factory() helper resolve ModelFactory classes, and it does not add ->for(), ->has(), ->asJSON(), or ->recycle() to legacy factories. Those remain class-factory-only features.factory() worlds. Laravel 8+ ships Illuminate\Database\Eloquent\Factories\Factory. The helper this package registers is a distinct global. Don't assume definitions "flow" between the two—mixing factory(User::class)->create() and UserFactory::new()->create() against the same model produces two separate definition trees.factory() undefined after install. In order of likelihood: (1) installed into require but the autoload map is stale—run composer dump-autoload; (2) a composer update removed it accidentally—confirm with composer show laravel/legacy-factories; (3) config/route cache holding an old provider map—run php artisan optimize:clear.LEGACY_FACTORY grep check in CI is a cheap, effective forcing function) rather than an indefinite deferral.ReturnTypeWillChange. If you are pinned to an older patch of Laravel 8 or 9 and hit an edge case, verify the release notes match your constraint before debugging your own code.composer show laravel/legacy-factories rather than assuming the framework version implies the package version.How can I help you explore Laravel packages today?