ramadan/custom-fresh
A Laravel package that customizes the migrate:fresh workflow, letting you refresh your database while preserving selected tables and controlling seeding. It simplifies resetting development databases without losing essential records, making repeatable local and test setups faster and less destructiv...
What the package is. ramadan/custom-fresh is a Laravel dev-tooling package that extends the migrate:fresh workflow so a configured set of tables is excluded from the drop (and, depending on implementation, preserved or re-populated) while the rest of the schema is rebuilt. It targets a real ergonomic gap: teams keeping reference data — countries, currencies, plans, permissions, feature flags, taxonomy — in the database and tired of re-seeding it on every fresh rebuild.
What changed in v2.2.1. This is a meaningful release for an evaluator, not a cosmetic patch. Four things shift the picture:
--drop-referenced option. The package is now doing FK-graph reasoning, which is exactly where naive implementations break on Postgres ordering.--drop targets a table that shares a create migration with related tables, and in non-interactive mode it preserves the entire related group rather than guessing. Fail-safe defaults in CI are the right design call.--drop flag and --drop-referenced option — the command is no longer purely subtractive. It now has its own flag semantics layered on top of Laravel's, which widens the surface area and the number of code paths to reason about.Architecture fit. Still small and well-contained: service provider, config file, command. Still dev/CI-only, no request lifecycle, no runtime coupling, no production blast radius by design. Two caveats, one old and one new. The old one stands: it borrows against migrate:fresh internals, which have shifted across Laravel 8→12, so a subclass or vendor-copy inherits a compatibility treadmill. The new one: migration-group detection implies it reads and correlates migration files with table names, which is a deeper coupling to Laravel conventions (file naming, Schema::create parsing) than a thin wrapper. That is more capable but more brittle than what we assessed previously.
Integration feasibility. Still low effort — composer require --dev, publish config, enumerate tables, alias the command in a Makefile/composer script. Half a day for a working pilot. The added validation means a misconfigured table name now fails fast at command invocation rather than silently, which shortens the pilot feedback loop. Still require-dev only, never in the production dependency graph.
Technical risk. The supply-side profile is unchanged in kind but improved in signal: single maintainer, zero dependents, low visibility, but now with a visible incremental release cadence (v2.2.0 → v2.2.1), a properly formatted changelog, and compare links. The previously flagged future-dated release timestamp is less concerning now that we can see a coherent tag progression — treat it as resolved-ish, but still confirm the tag history on the repo. Hazards, revised:
--seed, --drop-views, --drop-types. Still unaddressed, and now compounded by --drop / --drop-referenced flag interactions.--drop and --drop-referenced add combinatorial behavior. Two flags with an interactive prompt and a non-interactive fallback is a state machine; the release notes describe the intended behavior but not the exit codes. Confirm that validation errors and declined prompts produce a non-zero exit in CI, otherwise the fail-safe becomes a fail-silent.Key questions for the maintainer / spike. (Resolved items struck through.)
--drop-referenced; confirm exact behavior on Postgres FK ordering.--seed, --drop-views, and --drop-types? (still open)schema:dump) or migrations that create tables conditionally?Stack fit. Laravel-only, dev/CI-only. Sits in the same layer as seeders, factories, and RefreshDatabase. It complements rather than replaces db:seed; the healthy pattern remains idempotent seeders plus this package for expensive reference tables. Do not use it as a substitute for seeders.
Migration path. Pilot, pin, codify — largely unchanged, with two additions:
require-dev with a pinned constraint (^2.2 or exact); commit composer.lock.migrate:fresh --seed vs. the package command, then diff SHOW CREATE TABLE and row counts across every table. Any schema difference is a red flag.Compatibility. Verify the constraint against your actual Laravel/PHP versions before piloting. Confirm behavior on the driver your CI and staging actually use; an SQLite-only validation remains close to worthless for a drop-ordering- and FK-sensitive tool, and v2.2.1 makes the tool more FK-sensitive, not less.
Sequencing. Still a two-week background thread: week 1 spike and validation, week 2 build-vs-buy. The build-vs-buy calculus has moved toward buy. Previously the in-house option was "a few dozen lines"; with migration-group correlation, FK-referenced-parent warnings, validated inputs, and an interactive/non-interactive split, a faithful reimplementation is now a real multi-day piece of work with its own edge cases. In-house remains the right answer if you only need the simple skip-the-drop behavior and can accept schema drift on preserved tables — but if the spike shows the group and FK handling works on your driver, adopting is the higher-EV path than reimplementing it badly.
Fallback. Unchanged: native migrate:fresh plus fast idempotent seeders, or schema:dump for large baselines. Slower per rebuild, zero dependency risk.
Maintenance. Code footprint still small; the burden is governance plus now a slightly wider behavioral contract. The v2.2.1 changelog is a positive maintenance signal — disciplined, scoped, incremental. But still one maintainer, zero dependents, low visibility; plan for upstream going quiet. Keep the constraint pinned, own the config, and be ready to absorb the command. Quarterly check: does it support the current Laravel major, and is the repo still active?
Support. No vendor, no SLA, community issues only. Name an internal owner. Document the escape hatch (delete the dependency, restore the native command) so an on-call engineer does not have to reverse-engineer it — and now also document the --drop / --drop-referenced flag semantics, because they are non-obvious and team members will encounter them in the Makefile.
Scaling. No runtime scaling concern; zero production footprint. The relevant scale is team scale: every engineer running a local rebuild depends on the exclusion list being correct, and a wrong entry propagates to all environments at once. Modest real benefit in CI wall-clock where large reference tables are no longer re-seeded per run.
Failure modes and mitigations.
Ramp-up. A Laravel developer is productive within an hour; the config file is the only thing they must read. The real cost is cultural: teaching the team that "fresh" no longer means "everything is fresh," that preserved tables are a shared contract, and now that --drop exists and can override that contract. That needs a short written convention in the repo, not a training session.
TPM verdict. Still low-risk, dev-only tooling solving a genuine annoyance — but v2.2.1 materially improves the risk profile by replacing silent failure with loud failure on the highest-severity hazard, and it raises the credible capability bar enough that in-housing is no longer the obvious default. Recommended: timeboxed spike pinned to ≥ v2.2.1, exercise the failure paths and the non-interactive CI behavior explicitly, then prefer adoption over reimplementation if the driver matrix and --seed composition check out. Keep it out of the production dependency graph; keep it documented as part of the build.
How can I help you explore Laravel packages today?