byerikas/eloquent-query-cache
Eloquent Query Cache is a Laravel package for caching Eloquent query results, reducing repeated database hits and improving performance in read-heavy apps. It plugs into Laravel’s cache system to store and retrieve query results with minimal code changes.
Architecture fit. eloquent-query-cache is a Laravel-native composer package that layers query-result caching onto Eloquent's builder without requiring changes to the persistence layer. Architecturally this is a "decorator at the ORM boundary" pattern: it sits between application code and the database, keyed by model + query signature, and (per the package's stated design) relies on model events for invalidation. That is a good fit for read-heavy, Eloquent-centric Laravel services and a poor fit for anything with heavy raw-SQL, reporting/analytics queries, or cross-service write paths that bypass Eloquent. The v1.2.0 changes are both additive and narrow: exists() support closes a real functional gap (previously exists() either bypassed the cache entirely or behaved inconsistently relative to cached get()/count() calls, which is the kind of asymmetry that produces confusing production behaviour), and "extra property / function calls when creating builder instance" improves ergonomics so a cached builder can be constructed and chained like a normal builder (Model::cache()->where(...) rather than only via a terminal call).
Integration feasibility. Low. It is a standard composer dependency plus optional config publish; no schema changes, no new infrastructure beyond an existing Laravel cache store. There is no migration or backfill — adoption can be incremental, model by model. The main feasibility question is not "can we install it" but "can we trust cache correctness in our write paths," which is an application-design question rather than a packaging one.
Technical risk. Moderate, concentrated in three areas rather than in the code itself:
byErikas handle, and the changelog is one PR. That is a supply-chain and long-term-support consideration that outweighs the feature content.DB::table(), other services, manual SQL, seeders), and key collisions if the builder-to-key serialization does not capture bindings, scopes, or connection. The new exists() support is a correctness improvement, but it also means one more query shape whose invalidation semantics must be verified against the model-event strategy.exists() results changes timing guarantees for "does this row exist yet" checks — relevant for idempotency checks, uniqueness pre-validation, and polling loops.The release itself carries no breaking changes and no deprecations, so upgrading within the 1.x line is low risk.
Key questions.
with() eager loads?DB::table(), bulk upsert, raw statements)? Is there a documented manual flush API?exists() participate in the same key namespace and invalidation as get()/count(), or is it a separate key that could go stale independently?Stack fit. Strong for a conventional Laravel service (Laravel 9/10/11, PHP 8.1+) using Eloquent as the sole data-access path and already running Redis or Memcached for sessions/queues. Weak where the service is a thin read API over a warehouse, where query shapes are user-generated and unbounded, or where cache invalidation must be coordinated across services.
Migration path. Greenfield: adopt directly. Brownfield: do not retrofit globally. Introduce it per-repository or per-model, starting with the highest-read, lowest-write-churn models. Keep the existing repository/query-object boundary as the injection point so caching is togglable and removable without touching call sites. Because v1.2.0 is additive only, there is no forced upgrade work — treat it as the baseline version to start on.
Compatibility. Confirm the package's Laravel and PHP constraints against our lockfile before adding it, and confirm the chosen cache driver's tag support. If we run the file or database cache driver in any environment, caching correctness there must be validated separately, not assumed from the Redis-tested path.
Sequencing.
exists() caching) only after the base caching path is proven — these change behaviour for logic that is often correctness-sensitive.Maintenance. Low code footprint but a real ownership obligation: pin the version explicitly in composer.json (e.g. ^1.2), watch the repo for releases, and be prepared to fork or vendor if the package is abandoned. Budget a standing owner for cache-key and invalidation correctness — this is the kind of dependency that is invisible until it produces wrong data.
Support. No commercial support path. Internal support means one or two engineers who understand the key-composition and invalidation rules well enough to debug stale reads at 3am. Document those rules in-repo; do not rely on the upstream README as the operational runbook.
Scaling. Caching reduces database load roughly in proportion to read repetition, but shifts pressure to the cache tier: key cardinality grows with query-shape diversity, and unbounded/user-influenced query shapes are a memory-footprint hazard on Redis. Watch eviction rates and per-model key counts. Invalidation via model events can also produce write amplification on high-churn tables, where the cache may cost more than it saves.
Failure modes.
exists() false negatives/positives if the new path's invalidation diverges from get().Ramp-up. Low for installation (hours), moderate for safe operation (one to two engineer-days to build the invalidation test harness and gain confidence in key composition). The v1.2.0 features add negligible ramp-up cost on top of that, and the absence of breaking changes means no re-training for anyone already on 1.1.0.
How can I help you explore Laravel packages today?