Product Decisions This Supports
- Build vs. buy (cache layer): The package replaces what would otherwise be a 2–6 week internal effort to build query-result caching with correct invalidation. MIT license removes procurement/legal friction; 2.4k stars and a recent release cadence give reasonable confidence of community maintenance. This is a "buy" decision that costs an afternoon, not a quarter.
- Performance roadmap / latency budget: Directly supports decisions like "can we hit p95 < 300ms on catalog endpoints without a read replica?" and "do we need to vertically scale the primary DB this quarter?" It moves the conversation from infrastructure spend to configuration.
- Roadmap sequencing and deferral: Successful adoption lets us defer — not cancel — the read-replica, sharding, or denormalization workstreams. That reallocates engineering capacity to feature work, which is usually the highest-leverage PM decision available.
- Feature-level freshness contracts: The package's event-driven invalidation (create/update/delete on the model) defines the staleness envelope we can honestly promise. As of 13.2.0 this is now a dial, not a constant: TTL can be set globally and overridden per model, so we can encode freshness policy as configuration — aggressive TTLs for public listings and dashboards, short or disabled caching for surfaces with a tighter contract (checkout inventory, permissions, balances).
- Primary use cases to target first: read-heavy public content and catalog pages, admin list/index screens with repeat views, aggregated dashboard widgets, and any endpoint where the same query shape is issued many times per minute against slowly changing rows.
- Cost optimization: Fewer DB round-trips translates into smaller instance classes or headroom on existing ones — a concrete line item to defend in budget reviews.
- Risk posture decisions: Adoption is per-model and opt-in via a trait, so we can decide incrementally which domains take the caching risk rather than making a single platform-wide bet.
When to Consider This Package
Adopt when:
- The application is Laravel with Eloquent as the primary data-access path, and reads substantially outnumber writes on the models in question.
- PHP 8.3+ is available on the runtime we intend to deploy to. 13.2.0 raises the floor from 8.2; on 8.2 Composer pins you to 13.1.11, which lacks this release's correctness fixes. Treat the PHP version as a hard gate checked before the pilot, not after.
- A taggable cache store (Redis or Memcached) is already provisioned and shared across app servers. This is a hard prerequisite — file/database cache drivers don't support the tag-based invalidation this package relies on, and a per-server cache will produce inconsistent results behind a load balancer.
- The team is comfortable with write-path discipline: any write that bypasses Eloquent (raw SQL, direct DB access from another service, ETL jobs, triggers, sibling apps on the same database) will leave stale entries that this package cannot see or flush.
- Multi-tenancy is enforced inside the query (global scopes, bound parameters) so tenant identity is part of the cache key. If tenancy is enforced above the ORM — separate connections, session filters applied outside the query — treat cross-tenant leakage as a blocking risk and require a spike before committing.
- Strong consistency and read-your-writes are not required on the target surfaces; a short TTL or cooldown is an acceptable trade.
Look elsewhere when:
- The stack isn't Laravel/Eloquent, or the hot paths are hand-written query-builder/raw SQL that the trait won't wrap.
- You need surgical, row-level invalidation or hard consistency guarantees (financial balances, authorization checks, inventory holds).
- Models are write-heavy enough that invalidation churn matches or exceeds the read savings — the cooldown/throttling mechanism mitigates but doesn't eliminate this.
- Deep eager-loading graphs and aggregate queries cause invalidation fan-out to become more expensive than the original reads.
- Your hot queries lean heavily on macros, custom builder methods with arguments, closure
where() on scoped models, or eager-load constraints beyond simple where clauses. 13.2.0 deliberately routes several of these to uncached reads rather than risk a colliding key. That's the right call for correctness, but it means the hit rate on those paths will be lower than a naive benchmark suggests — measure before promising a latency win.
- You require a formally supported, vendor-backed dependency with an SLA. Note the metadata shows zero tracked dependents; treat the star count as popularity signal, not production proof, and run your own pilot before standardizing.
If already running an earlier 13.x line: this release is a required upgrade rather than an optional one. Several fixed defects let a query read cache entries written under a key another query also used — i.e. potentially the wrong rows. Plan the upgrade as a small, scheduled piece of work: bump PHP to 8.3, fix any untyped $isCachable declarations and any trait rules referencing Cachable::newBaseQueryBuilder, run php artisan modelCache:clear as a deploy step, and expect a one-time cold-cache latency blip while keys rebuild. Also note that modelCache:clear no longer wipes the entire cache store — if any script or runbook used it as a blunt "clear everything" button, that script now needs php artisan cache:clear instead. That's a safety improvement, but it silently changes existing operational behavior.
How to Pitch It (Stakeholders)
To executives: This is a low-cost, reversible performance lever. It's a mature, MIT-licensed Laravel package adopted by adding one trait to selected models — no schema migration, no new infrastructure, no rewrite. Expected outcomes are lower database load and better response times on our read-heavy surfaces, which buys us time before committing to read replicas or re-architecture. The latest release also adds per-model and global TTL settings, so we can tune how fresh each surface is instead of making one blanket trade — and it closes a class of cache-key defects that could have served the wrong rows, which lowers the risk of the pilot. Success is measured in DB CPU, p95 latency, and cache hit rate over a four-week pilot, with removal of a single trait as the rollback.
To engineering: Opt-in per model via Cachable; automatic invalidation on Eloquent create/update/delete events using cache tags; per-query controls (cacheFor() TTLs, dontCache(), disableCache(), crossCache()) plus global and per-model TTL configuration, and a cooldown setting for write-heavy models. No schema changes. Three upgrade constraints to schedule for: PHP 8.3 minimum; $isCachable must be declared as protected bool; and the trait no longer carries newBaseQueryBuilder(), so any trait alias/precedence rule naming it must be deleted. Run modelCache:clear immediately after deploy so no query reads an entry written under the pre-upgrade key format. The one real product constraint is unchanged: writes must go through Eloquent — raw SQL and out-of-band writers become invisible to invalidation, so we'll document that boundary and lint for it.
Framing the risk: Start with two or three bounded, read-heavy models, define hit-rate and latency targets up front, and require an explicit exit criterion (removal of the trait) if hit rates are poor or staleness incidents occur. Because 13.2.0 sends several hard-to-key query shapes to the database by design, set hit-rate expectations from a measured baseline on our own query mix rather than from the package's general reputation. This is a pilot decision, not an architecture decision — which is exactly why it's a cheap one to make.