Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Model Cache Laravel Package

ymigval/laravel-model-cache

Transparently caches Eloquent query results with zero syntax changes, auto-invalidating on create, update, delete, and restore. Configurable TTL, stores, and tags for read-heavy Laravel apps.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit The package uses a trait (HasCachedQueries) that overrides newEloquentBuilder() to return a CacheableBuilder, making every get()/first() on that model cache-aware with no call-site changes. This is a shallow-footprint, deep-semantics design: the code change is one use statement per model, but the behavioral change is global to that model's reads. For a read-heavy Laravel app on Redis, that's an attractive ratio. For a TPM, the important framing is that this is implicit caching — the default state of the system becomes "reads may be stale," and that is a product/correctness decision, not just a performance one.

Cache keys derived from SQL + bindings + model class are the architecture's load-bearing element. They give you correctness for free on simple where x = ? queries and become the primary scaling liability on dynamic queries (whereIn with variable-length arrays, pagination offsets, user-scoped filters, sort permutations). There is no documented key-cardinality bound, no stampede/lock protection, and no hit/miss instrumentation — all three are things the adopting team will have to build or size around.

Invalidation is event-based (created, updated, deleted, restored) plus a ModelRelationships trait for pivot operations. That covers idiomatic single-model Eloquent writes. It does not cover writes that bypass model events — Model::where(...)->update(), upsert(), query-builder inserts, seeders/imports, raw SQL, or another service writing to the same database. Those are the silent-staleness paths and they are common in mature codebases.

Integration feasibility Low friction mechanically: composer require, optional config publish, add the trait. The hard dependency is a tag-capable cache store (Redis/Memcached/database). File and Array drivers "work" but fall back to clearing the entire cache on invalidation — acceptable in dev, not in production. Provisioning a dedicated Redis store and prefix is effectively a prerequisite, not a nicety.

Technical risk

  • Builder override collisions. Any model that already has a custom Eloquent builder, or any package that decorates the builder (search/scout-style packages, query-builder helpers), will conflict. The app's builder would have to extend CacheableBuilder, which is doable but couples your builder hierarchy to a third-party class.
  • Signature drift across Laravel 8–13. Illuminate\Database\Eloquent\Builder is not a stable interface across five majors. Claiming Laravel 13 support is a forward-compatibility claim that must be verified per release, and a broken override fails loudly at query time.
  • Serialized model objects in cache. get() returns hydrated models; if those are stored serialized, a deploy that changes a model class can invalidate readability of live cache entries. Deploy-time flush becomes mandatory, not optional.
  • Transaction and connection semantics. Nothing in the README addresses whether results queried inside an open transaction get cached, or whether the cache key includes the DB connection — a real concern for multi-connection/multi-tenant setups.
  • Adoption signal is weak. 78 stars, zero dependents, single maintainer, MIT. No dependents means no third-party validation of edge cases.

Key questions to put to the maintainer / spike

  1. What happens on cache-backend failure — degrade to DB, or throw?
  2. Is the connection name and tenant scope part of the cache key?
  3. Do chunk(), cursor(), lazy(), paginate(), and aggregate methods (count(), exists()) cache, pass through, or behave inconsistently?
  4. Is there per-request or per-query bypass beyond withoutCache()?
  5. Is there a test suite and a CI matrix across the claimed PHP/Laravel versions?
  6. Any stampede protection or TTL jitter?

Integration Approach

Stack fit Best fit: Laravel 8–12, PHP 8.x, Redis already in the stack, read-heavy domain models with low write rates and tolerant freshness windows (CMS content, catalogs, taxonomy, feature/config lookups, public profile pages). Poor fit: money, inventory, permissions, or anything where a stale read is a customer-visible defect; and apps whose writes largely bypass Eloquent events.

Migration path Opt-in per model is the key property — this is an incremental rollout, not a cutover. The enabled config toggle gives a global kill switch, which is the rollback mechanism. Exit cost is also low: removing the package means deleting one trait and, where needed, replacing implicit caching with explicit Cache::remember — the coupling is concentrated in model declarations.

Compatibility gates before rollout

  • Confirm every model you intend to tag has no custom builder and no builder-decorating package in its query path.
  • Confirm no write paths use mass update()/upsert()/raw SQL on those models without a compensating flush.
  • Confirm the cache store is tag-capable and isolated by prefix from session/queue/app cache to avoid flush collateral damage.

Sequencing

  1. Provision and isolate. Dedicated Redis cache store + cache_key_prefix, distinct from the default store. Size memory and pick an eviction policy deliberately (allkeys-lru can evict hot keys; noeviction throws).
  2. Land dark. Install, publish config, set enabled = false. Run the full test suite; establish a baseline for query counts and p95 latency on the target models.
  3. Pilot one model. Enable the trait on a single high-read, low-write model. Instrument DB query volume, cache hit rate, and Redis memory/key count. Watch key cardinality for a full traffic cycle, not an hour.
  4. Close the invalidation gaps. Enumerate every write path to the piloted model; add flushModelCache() calls or the mcache:flush command to importers, bulk jobs, admin tools, and any non-Eloquent writer. This is the step most likely to be skipped and most likely to cause an incident.
  5. Wire deploy hygiene. Add php artisan mcache:flush (scoped per model where possible) to the deploy pipeline; full flush is mandatory after model/schema changes because of serialized cached models.
  6. Expand by domain. Add models in cohorts, gated on observed hit rate and zero staleness reports. Prefer explicit remember() TTLs per model over the 60-minute default — different write rates need different windows.
  7. Revisit per Laravel major. Re-run the pilot on each Laravel upgrade before bumping.

Operational Impact

Maintenance Single-maintainer package with no dependents. Treat it as fork-ready: the surface is small (one builder, two traits, one command), it is MIT, and it is vendorable. Budget for owning it — specifically for tracking Eloquent\Builder signature changes on every Laravel major. Without that ownership assumption, an abandoned package becomes a hard blocker on framework upgrades.

Support Community-only via GitHub issues; no SLA, no commercial backstop. Internal documentation should capture the caching semantics, the flush command, and the "which models are cached and why" inventory, because the failure mode is invisible by design.

Scaling The scaling constraint is cache key cardinality, not the cache backend. Every distinct SQL+bindings combination becomes a key; attacker- or user-controlled filter parameters can inflate this without bound, which is both a memory cost and a mild DoS vector. Second constraint is stampede: a hot key expiring under load pushes a burst to the database at exactly the moment the cache is least helpful. TTL jitter and request-level de-duplication are mitigations you would own. Third is cold-start after a flush — the README suggests cache warming but ships none.

Failure modes, ranked by severity

  1. Silent staleness from event-bypassing writes — highest severity because nothing alerts. Mitigation: write-path audit plus scheduled/scoped flushes.
  2. Wrong-tenant or wrong-connection reads if tenant/connection is not in the key — a data-leak class bug, not a performance bug. Must be verified before pilot.
  3. Cache-backend outage — whether the app degrades to DB or errors out determines whether this package is a performance layer or a new single point of failure.
  4. Key explosion / Redis eviction — manifests as a cache that slowly stops helping while consuming memory; needs key-count and eviction-rate monitoring.
  5. Builder conflicts on upgrade — loud, caught in CI if the test suite exercises the cached models.
  6. Full-cache flush on non-tag drivers — a performance cliff, and collateral damage to unrelated cache entries.

Ramp-up Developer cost is low (one trait, syntax unchanged), but the conceptual cost is real: engineers must internalize that Post::where(...)->get() may return stale rows and that non-Eloquent writes do not invalidate. The README is unusually thorough for a package this size — implicit vs. explicit caching, withoutCache(), scopes, and flush commands are all documented — but it is silent on multi-tenancy, transactions, key cardinality, and failure behavior, which are precisely the operational questions that matter. Plan a short internal onboarding note with a rule of thumb: cache the model only if you can enumerate every writer to it.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/command-executor-lib
tagixo/document-builder
tagixo/page-builder
tagixo/mail-builder
tagixo/form-builder
primix/primix
tagixo/core
alesima/laravel-azure-service-bus
tomshaw/shopcart
likyly/laravel
darthsoup/shoppingcart
tdt/core
labyrinthe/connect-php
encore2/laravel-admin2
cboxdk/laravel-console-kit
shapecode/doctrine-dbal-datetimeutc
gilads-otiannoh254/inertia-protocol
dakiquang/laravel-oauth-refresh-lock
woda/laravel-worktrees
dalefranks/ramasite