evotodi/seed-bundle
Symfony/Doctrine bundle for loading and unloading seed data before your initial production push. Define seed commands with ordering to populate tables like states or initial admin users, unlike DoctrineFixturesBundle, which targets development.
Seed base command requiring seedName(), an optional getOrder(), and load()/unload() verbs returning exit codes — so the "buy" case rests less on code volume and more on the enforced naming convention, the ordered registry, and the glob-based selection grammar you get for free. If your team already runs Symfony console commands fluently, building is a legitimate choice and the cost is ongoing ownership of a convention, not of an algorithm.--break (halt on first failure) becomes your deployment's fail-fast contract.seed:load prod/users/* and seed:load --skip country mean a single seed corpus can serve multiple environments and tenants through naming conventions (prod:users:eu, dev:prices) rather than through separate codebases or database dumps. This is a real roadmap enabler for staging/demo tenants and regional rollouts.disableDoctrineLogging() wrapper because Doctrine logging consumes significant memory during bulk writes, and returns exit codes so failures are visible to CI and deploy tooling. Those are small details that indicate the authors targeted production use; they also become your responsibility to exercise and verify.Adopt only when all of the following hold:
*Seed suffix requirement, seedName() became the only naming mechanism, the config file was dropped). Budget for that migration surface if you are coming from an older major.getOrder() value load semirandomly; the README itself warns that this interacts badly with --from. In practice this means either assigning unique sequential order values or always verifying with --debug before a production run. That is a discipline cost, not a bug, but it must be owned.Look elsewhere — or write the ~100 lines yourself — when:
db:seed, DatabaseSeeder, and model factories in core, so adopting this would mean importing Symfony console/DI assumptions into a Laravel app for zero functional gain. For a Laravel roadmap, the correct product decision is to formalize your existing seeders and factories, not to evaluate this package.seed:load on existing rows is your problem to solve inside load(), and the unload() example is a bare DELETE FROM user — destructive by default.For executives (one paragraph): Today we have no consistent, auditable way to populate production reference data — the first admin account, roles and permissions, country and state lists, plan definitions. Those steps live in tribal knowledge, wiki pages, and one-off SQL, which means every new environment is a manual, error-prone event with no defined rollback and no clear owner. This package offers a small, MIT-licensed, production-oriented way to make those datasets first-class, command-addressable artifacts: one command to load, one to unload, with explicit ordering and the ability to target a subset by environment or region. The strategic value is not the library — it is the forcing function. Adopting it means we finally draw the line between reference data that must exist for the product to work and test fixtures that must never reach production, and we assign an owner to that line. The cost is one dependency and a conventions document; the risk is low because the code is narrow enough to fork if needed, but the dependency is single-maintainer and near-zero-adoption, so we should treat it as "buy the convention, not the support contract." Recommended decision: evaluate on one service, not fleet-wide.
For engineering (summary): This is a Symfony 6+/PHP 8+ Doctrine bundle. You write a Seed subclass per dataset, declaring a static seedName() (colon-separated, mirroring console command naming) and an optional getOrder(). The bundle auto-registers two global commands (seed:load, seed:unload) plus one per seed (seed:user load|unload). Selection supports glob matching with colons and slashes interchangeable (prod/users/*, prod/**/*), plus --skip, --from, --break, and --debug. It provides disableDoctrineLogging() because Doctrine logging is memory-hungry during bulk writes, and requires load()/unload() to return exit codes so failures propagate to CI. Known sharp edges to design around: equal getOrder() values load semirandomly and interact badly with --from — assign distinct sequential orders and gate production runs on --debug. unload() is whatever you write; the documented example is an unqualified DELETE, so add guards. There is no idempotency, no dependency graph, no transaction wrapper, and no run-ledger — if you need any of those, you are building them in load().
For the product and ops leads: The pitch is a runbook change, not a codebase change. Before adopting, answer three questions in writing: (1) Which exact datasets are production-critical reference data, and which are dev fixtures? (2) Who is authorized to run seed:load against production, and is that a deploy-pipeline step or a human action? (3) What is the recovery path if a seed loads incorrectly — is unload acceptable, or do we need a backup-and-restore step? If those three answers are clear, this package is a cheap way to make the process explicit and repeatable. If they are not, adopting it will simply automate an undefined process. Also flag the privileged-account question: seeding the initial admin user means a known credential exists in source control unless you parameterize it — decide now that this is injected from a secret, and that rotation happens immediately post-deploy.
Framing to avoid: Do not position this as "a Laravel seeding package" or as a replacement for Laravel's core db:seed — it is neither, and the first engineering review will lose confidence if the proposal misstates the stack. Position it narrowly: a Symfony-native, operator-invoked, production-seeding convention, worth a scoped pilot on a single Symfony service, with a documented fork-and-own fallback given the maintenance profile.
How can I help you explore Laravel packages today?