elipzis/laravel-cacheable-model
Add automatic select-query caching to any Laravel Eloquent model with a single trait. Configure TTL, prefixes, and unique identifiers per model, skip manual cache calls, and rely on automatic flushing for inserts, updates, and deletes. Works with Redis, memcached, and more.
Architecture fit. The package is a trait-plus-QueryBuilder-override design: adding use Cacheable to a model swaps in CacheableQueryBuilder, which hashes the query signature and reads/writes results against the configured cache store. This is an attractive fit for Laravel shops wanting zero-call-site-change caching, because it preserves idiomatic Eloquent (Model::query()->where(...)->get()) and requires no refactor of repositories or controllers. Architecturally, though, it sits inside the ORM's query path rather than beside it — a deliberately invasive placement that makes correctness and performance depend on how faithfully the builder can reproduce a cache key from arbitrary query state. It is best understood not as a general caching layer but as a narrow optimization for a small number of read-heavy, slow-changing reference models.
Integration feasibility. Mechanically trivial: one composer require, one optional vendor:publish for config (TTL, prefix, identifier, logging), one trait import per model. Opt-out (withoutCache()) and manual invalidation (flushCache()) exist for escape hatches, and the package supports tagged caches with expiry cleanup (0.5.0) and per-model config overrides via getCacheableProperties(). The realistic effort is not installation but validation: confirming that every query shape your application actually issues (whereIn with raw Expressions, whereNull, aggregates, pagination, chunking, eager loads, exists(), raw selects) either caches correctly or falls through safely. Note the low adoption signals — 158 stars, zero dependents, single-maintainer cadence — which shift due diligence burden onto us.
Technical risk. The dominant risks are correctness and blast radius:
whereIn with Expression in 0.4.1, whereNull undefined values key in 0.6.0). Each such bug class manifests as a wrong result returned to a user, not an error — the worst failure mode.DB::, and cross-model dependencies (e.g., cached Category results changing when Product rows change) will silently serve stale data. flushCache() exists but must be invoked by us — that is application logic the package cannot own.Key questions.
Stack fit. Requires Laravel 11–13 / PHP 8.3–8.5 per recent releases; assumes a real cache store (Redis or memcached strongly preferred over file/database, since this package multiplies cache operations per query and tagged-cache behavior matters). Fits a conventional Laravel monolith or modular monolith with a repository-or-Eloquent data layer. It does not fit architectures where data access is already abstracted behind a read-model/CQRS layer, or where an existing caching strategy (response cache, Redis-backed repository cache, Octane-aware caches) is already in place — layering this on top creates two competing invalidation authorities.
Migration path. Incremental and reversible:
logging.enabled = true initially to observe hit/miss and key behavior.getCacheableProperties() rather than relying on global defaults.Rollback is a one-line trait removal per model, which is a genuine strength for a TPM-managed rollout.
Compatibility. Watch for: query-builder features the package may not key correctly (subqueries, whereHas, unions, raw expressions, withCount); pagination and cursor()/chunk() paths where cached rows may be served inconsistently; multi-tenant scoping implemented via global scopes — a global scope that varies per request must be reflected in the cache key, and this is the single most likely production incident vector. Also confirm behavior under Laravel Octane, where long-lived workers plus cache state can produce surprising cross-request effects, and confirm the cache prefix isolates environments (staging vs. production) and tenants.
Sequencing.
flushCache(), and on what events) and add a test that fails if a write path bypasses Eloquent.Maintenance. Low ongoing code maintenance, moderate-to-high cognitive maintenance: every engineer touching a cacheable model must understand that query semantics now include cache semantics. That is a real onboarding and code-review tax. Dependency maintenance is light but not zero — we inherit the maintainer's Laravel/PHP support cadence and must track it. Budget roughly one engineer-day per quarter for version-bump verification, plus incident time if a key-collision bug surfaces.
Support. No commercial support; MIT-licensed community package with a single primary maintainer and 158 stars. Support model is effectively self-support: read the changelog, read the source (small and readable), or fork. This is acceptable for a non-critical read optimization and unacceptable for anything on a revenue-critical or compliance-critical path. Do not place this in front of billing, permissions, or inventory-availability reads.
Scaling. Scales well horizontally for read-heavy workloads — the whole point is offloading the database, and Redis-backed stores extend that benefit across app servers. Vertical concerns: cache memory growth from many distinct query signatures (a query with high-cardinality whereIn values generates near-unique keys and near-zero hit rate — a silent waste of memory and CPU). Set TTLs conservatively, monitor key count and eviction rate, and be prepared to cap or exclude models that generate key sprawl. The per-query overhead is constant and small but universal across cacheable models, so the benefit only materializes where hit rates are high; instrument hit ratio rather than assuming it.
Failure modes.
Ramp-up. For a competent Laravel engineer: under half a day to install, configure, and cache a first model; one to two days to build genuine confidence in key correctness and invalidation for that model. The docs are adequate for the happy path and thin on internals — expect engineers to read the query builder source to answer "will this query be cached correctly?" Overall ramp-up is fast, but trust ramps slower than usage, and the rollout plan should reflect that gap.
How can I help you explore Laravel packages today?