Product Decisions This Supports
- Build vs. buy for the caching layer. Most Laravel teams eventually write a hand-rolled
Cache::remember() wrapper in repositories or controllers. That work is typically 2–4 sprints of engineering plus ongoing invalidation bugs. This package is a one-line Composer dependency plus a trait — it directly answers "do we build our own model cache or adopt one?" with a credible buy option for read-heavy domains.
- Buying runway on performance instead of architecture. Deciding between (a) scaling the database (read replicas, bigger instance), (b) an expensive query-optimization pass, or (c) cheap caching as a stopgap. This package is the cheapest of the three and can be piloted in a day, letting you defer infra spend while you measure whether the bottleneck is actually query volume.
- Scope of a performance initiative. It identifies a concrete, low-effort workstream: "turn on caching for the 5 hottest, read-mostly models" rather than a vague "make the app faster" epic. That is a scope a PM can actually schedule and measure.
- Roadmap sequencing for read-heavy surfaces. Catalogs, CMS pages, marketing content, public API read endpoints, dashboards, and settings/config models are natural pilot candidates. Knowing this exists lets you sequence caching after correctness work but before a re-architecture.
- Invalidation and operational policy. It forces a decision the team otherwise defers: what cache driver we standardize on (tag support effectively means Redis/Memcached in production), what TTL defaults are acceptable per model, and where
php artisan mcache:flush sits in the deploy runbook. That is a real architectural decision this package surfaces early.
- Risk triage on stale data. The package's automatic event-based invalidation is its main value and its main liability. Adopting it forces an explicit answer to "which of our data can tolerate up to N minutes of staleness?" — a question PMs should be asking anyway.
- Third-party dependency policy review. With 78 stars, 0 dependents, and a single maintainer, it's a test case for how much dependency risk the org accepts in the request path.
When to Consider This Package
Good fit when:
- The workload is read-heavy and write-light on the candidate models (content, catalog, reference data, settings) — caching wins and invalidation is rarely triggered.
- You're on supported versions (Laravel 8–13, PHP 7.4–8.4) and the app isn't deeply coupled to custom query-builder extensions.
- Redis or Memcached is already in the stack. Tag-based invalidation is what makes selective flushing possible; without tags, the fallback clears the entire cache, which is unacceptable in production.
- All writes to the cached tables go through Eloquent. Invalidation rides on model events; raw SQL, bulk imports, queue workers in other services, or a second application writing to the same database will silently leave stale entries.
- Correctness tolerance exists: stale-by-minutes is fine for a product listing, not for inventory counts or balances.
- The team is small and would rather not own a bespoke cache layer.
Look elsewhere when:
- You need strong consistency or the data is transactional/financial.
- You need vendor support, SLAs, or a large maintainer base — this is a single-maintainer package with essentially no downstream dependents, and it hooks into the query builder, the most load-bearing part of Eloquent.
- Queries return large result sets or heavy pagination; caching full result payloads inflates memory and can cost more than the query.
- The app relies on custom builders, macros, or packages that also override
newEloquentBuilder() — transparent replacement of the builder is a broad blast radius and can collide with other extensions.
- You're caching N+1-prone relational graphs; invalidation across pivots and relations gets subtle fast (the
ModelRelationships trait exists precisely because this is hard).
- You need observability into hit rate and memory out of the box — the package gives you caching, not measurement.
- The real fix is cheaper: an index, a missing eager-load, or fixing a bad query is usually higher ROI than caching a bad query.
Adoption criteria / guardrails before saying yes:
- Pilot on 1–2 models behind a feature flag, not application-wide.
- Baseline p95 latency and DB query volume; require a measured improvement, not an assumed one.
- Wrap usage at the repository/model boundary so removal is a revert, not a rewrite.
- Pin the version and explicitly test the Laravel upgrade path.
- Ban tag-less cache drivers in production.
- Add
mcache:flush to the deploy and data-import runbooks; require confirmation steps for full-cache flushes.
- Instrument cache hits/misses — if you can't state the hit rate after two weeks, you can't justify keeping it.
How to Pitch It (Stakeholders)
To executives: "We have a cheap, reversible experiment for database load and page latency on our read-heavy screens. It's a small open-source library — one dependency and one line per model — and we can measure the result on two models in about a week before committing to anything. If it works, we defer read-replica and instance-size spend this quarter; if it doesn't, we remove it. Cost is low, downside is contained, and the decision is data-driven rather than architectural."
To engineering: "It swaps the Eloquent builder for a cache-aware one behind a trait, so existing query syntax is unchanged and get()/first() hit the cache automatically; there are also explicit getFromCache()/firstFromCache() methods for readability. Invalidation is event-driven on create/update/delete/restore, with a ModelRelationships trait covering pivot attaches/detaches/syncs, plus mcache:flush and flushModelCache() for deploys and imports. Constraints we accept: Redis/Memcached for tag support (no file/array in production), all writes must go through Eloquent, and we pilot on a limited model set first because it's a single-maintainer package that overrides a core builder method. We'll pin the version, add hit-rate instrumentation, and keep it behind a repository boundary so we can rip it out."
The honest one-liner for both: it's a low-cost bet with real but bounded risk — worth a measured pilot, not worth a whole-app rollout on day one.