pxlrbt/laravel-database-state
Manage and apply named states to your Laravel database, making it easy to switch between predefined datasets for testing, demos, and local development. Define states once and reuse them across environments.
Build vs. buy for "reference data as code." Every product depends on a small set of rows that must exist for the app to function: roles, permissions, plan tiers, currencies, countries, default system settings, feature-flag baselines. Today that is typically handled by ad-hoc seeders, a wiki runbook, or a manual DBA step at launch. This package is a cheap alternative to building an in-house, idempotent "apply state" command — roughly half a day to a day of engineering, plus the ongoing cost of owning and maintaining it. The v2.0.0 release (first-party test suite, modernized dev dependencies) lowers the cost of the "buy" side because a fork now inherits tests rather than arriving naked.
Environment parity as a roadmap item. It gives the team a first-class, repeatable way to promote critical state across local → staging → production. That directly supports decisions like multi-region rollout, DR/restore drills, spinning up new tenant or sandbox environments without hand-holding, and onboarding new engineers onto a database that "just works."
Incident prevention over incident response. The highest-value use case is eliminating the recurring class of Sev-2 bugs where a deploy succeeds but the app breaks because a required permission, plan, or lookup row is missing in production. That is a budget line item — on-call load, rollback frequency, deploy confidence — a PM can justify in one sentence.
Scope decisions for RBAC and monetization work. If the roadmap includes roles/permissions (Spatie-style) or plan/entitlement catalogs, "where does the canonical list of permissions live, and how does it get to prod?" becomes a design decision made at spec time rather than firefighting time. This package is one concrete answer, and choosing it early avoids a rewrite mid-quarter.
Test-suite velocity as a secondary lever. The snapshot/restore capability — capture a known-good DB once, reset in seconds between test runs — attacks CI wall-clock time on large schemas and slow seeders. That is a developer-experience metric that shows up in PR cycle time, and a credible argument for headcount-neutral productivity gains.
Clarifying the data-type boundary. It forces an explicit distinction between schema migrations, reference state, and transactional data. That boundary is useful when scoping compliance, audit, and data-ownership questions — reference data is reproducible and owned by engineering; user data is not.
Explicitly not a fit for user-generated or high-churn data. It supports critical, deterministic, low-volume state. It is not a backfill tool, a bulk import mechanism, or an analytics pipeline, and should not be scoped into those problems.
Consider adoption when:
migrate and optimize where a state-apply step fits cleanly.Look elsewhere when:
updateOrCreate churns updated_at on every run. If you need transactional apply, drift detection with alerting, or strict ordering across dependencies, plan to build that layer yourself on top.To executives — one paragraph: A meaningful share of our deploy incidents and on-call pages come from a boring cause: production is missing a permission, a plan tier, or a settings row that exists everywhere else, and the app breaks in a way that is invisible until a customer hits it. This package makes that critical state explicit, version-controlled, and re-runnable, so it ships with the deploy instead of being hand-maintained in a runbook. Adoption cost is roughly a day of engineering, there is no new service to run or vendor to pay, and it converts a recurring class of Sev-2 incident into a solved problem. Secondarily, its snapshot/restore capability can cut CI wall-clock time on slow test suites, which shows up in PR cycle time.
To engineering — the honest version: It is a small, MIT-licensed, Laravel-native package with an Artisan surface that is essentially the entire public API, plus a config file for state paths, connection, and storage. v2.0.0 added a first-party test suite, which is a real maturity signal but not an API-stability guarantee — pin the exact version and diff the compare changelog before bumping. The recommended first move is narrow: extract one domain (roles and permissions) into one state class, make every write updateOrCreate against a deliberate natural key, wire syncWithoutDetaching for pivots, and call the same class from DatabaseSeeder so local and production share one definition. Verify against a restored production snapshot or a staging clone before it touches a real deploy. Then extend to plan tiers and system settings as separate, independently reviewable classes. Keep the snapshot/restore side for test suites only after the state classes are trusted, and only into the same driver and framework version CI runs on.
What we are deliberately buying: a single source of truth for low-volume, deterministic reference data, promoted through the same pipeline as code. What we are deliberately not buying: schema management, tenancy orchestration, backfills, or anything touching user-generated data. What we still own: ordering and foreign-key dependencies, cache invalidation after apply, environment guards (assume the package does not block production), a --dry-run habit, and the judgement not to delete rows in production.
How can I help you explore Laravel packages today?