Monday morning. Fresh bin/magento setup:install, admin user created, and a catalog that looks like a warehouse after a fire sale. Zero products, zero customers, zero orders. You open the frontend to demo something and all you've got is a sad "default" category with nothing under it.
Every Magento dev has been here. The official sample data helps for about two minutes, then you need 1,000 orders, a mix of product types, realistic customers, and some CMS pages to click through. You end up with a Gist of hand-rolled scripts that break on the next minor version.
I wanted the Laravel seeder experience in Magento. So I wrote one.
The 30-second pitch
composer require runasroot/module-seeder --dev
bin/magento module:enable RunAsRoot_Seeder
bin/magento setup:upgrade
bin/magento db:seed --generate=order:1000That last line gives you 1,000 orders across realistic lifecycle states, with auto-generated customers, products, and categories wired up underneath. No fixture files, no SQL dumps, no hand-rolled factories.
How it works
Drop a file in dev/seeders/ that ends in Seeder.php, Seeder.json, or Seeder.yaml. They all share the same shape.
# dev/seeders/CustomerSeeder.yaml
type: customer
data:
- email: john@test.com
firstname: John
lastname: Doe
password: Test1234!Then bin/magento db:seed runs everything in the folder. Need loops or conditional logic? Use a class-based seeder that implements SeederInterface and get full DI.
Or skip files entirely and lean on Faker.
bin/magento db:seed --generate=product:500,customer:200 --locale=de_DE --seed=42That's 500 products, 200 customers, German locale, deterministic output. Same --seed value, same data, every run. Great for CI.
The part I actually care about
Three decisions that I think matter.
Dependencies resolve themselves. Ask for order:1000 and the generator works backwards. Orders need customers, so it makes 200 (1:5 ratio). They need products, so it makes 50. Products need categories, so it makes 10. You get the whole graph without writing it out.
All five product types. Simple, configurable, bundle, grouped, downloadable. Plain --generate=product:N gives you a weighted mix that roughly matches what real stores look like (70% simple, the rest spread). Configurables auto-spawn 6 hidden children across 3 colors and 2 sizes. Bundles link to real simples in the catalog. Downloadables come with Faker-generated .txt files on disk so the storefront flow actually works end to end.
Orders span the lifecycle. Not just new rows in sales_order. You get invoiced processing orders, shipped complete orders, canceled, holded, closed with credit memos. Each state goes through the real Magento services (InvoiceService, ShipmentFactory, CreditmemoManagementInterface), because that's the only way you catch the observer chains that reset state mid-transaction. I learned that one the hard way.
Performance
Seeding 5,000 products on a fresh Mage-OS box used to take ages. The seeder batches iterations into DB transactions of 50 entries each, which cuts per-iteration commit overhead roughly in half. A failing row rolls back its batch and the run continues. No more losing 4,000 good products because number 4,001 hit a unique-key collision.
Runs with 10 or more entities render a live Symfony Console progress bar per type. Smaller runs stay compact. Nothing to configure.
Where it lives
github.com/run-as-root/magento-2-seeder. MIT. Works on Magento 2 and Mage-OS, PHP 8.1+. The examples/ folder has a seeder per entity type you can copy into your own dev/seeders/.
If your team still passes around a demo-dump.sql file in a Slack DM, you can stop doing that now.