ahmedzidan/laravel-cacheable
Laravel Cacheable adds automatic caching to your Eloquent models, so frequent queries are served from cache and invalidated on create, update, or delete. Drop in the trait, configure a TTL, and cut database load with almost no code changes.
Architecture fit
rinvex/laravel-cacheable (published under ahmedzidan/laravel-cacheable) is a trait-based query-result cache for Eloquent. It works by swapping the model's query builder so every get(), first(), count(), paginate(), and aggregate call is hashed into a cache key derived from the generated SQL plus bindings, then stored against a per-table tag. Writes and deletes flush the relevant tag. Architecturally this is a cross-cutting concern pushed down into the persistence layer — it fits cleanly into a conventional Laravel monolith or modular monolith where models are the single access path to data, and where a tag-capable cache store (Redis, Memcached) is already provisioned.
It does not fit event-driven, CQRS, or read-model architectures, and it fits poorly with any codebase that routinely reaches for the raw query builder, DB::table(), or hand-written SQL — those paths bypass the cache entirely, so you get inconsistent read semantics between Eloquent and non-Eloquent code.
Integration feasibility
Integration is mechanically trivial: composer require, add the trait to target models, ensure a tag-capable cache store, set a TTL. There is no service provider wiring to reason about, no config surface beyond the cache store, and no schema changes. The cost is not in installing it — it is in validating correctness. The package makes caching implicit: a developer reading User::where(...)->get() has no local signal that they are reading a cached snapshot. That implicit behaviour is the real integration risk, and it is a review-and-conventions problem, not a technical one.
Technical risk
The dominant risk is lifecycle: the repository is archived and explicitly marked abandoned, with 107 stars and zero dependents on the record. That is effectively no production user base and no maintenance. Concretely:
newEloquentBuilder / newBaseQueryBuilder and subclasses Eloquent's Builder and Query\Builder. Laravel has changed return types, added strict signatures, and altered builder internals repeatedly across 8.x–11.x. Compatibility beyond the Laravel version it was last released against is unverified and will not be fixed upstream.whereRaw with non-deterministic fragments, NOW()-style functions, connection-specific table prefixes, or tenant-scoped global scopes can collide or serve cross-tenant data if scoping is not part of the key. Stale reads after writes that occur outside the model layer (queue workers using raw SQL, other services writing the same tables, DB triggers) are guaranteed and undetectable.Net: low integration risk, high lifecycle risk, medium-to-high correctness risk.
Key questions
app/ or an internal package and own it, versus depending on an archived repository?Stack fit
Best fit: Laravel 8–10 on PHP 8.0–8.2, Redis already in the stack, models as the sole data access path, read-heavy workloads with expensive query shapes (multi-join listings, aggregate dashboards, filter-heavy index pages). Poor fit: Laravel 11+, multi-tenant SaaS, services with mixed ORM/raw-SQL access, teams without an existing cache-invalidation discipline, or anything with a compliance requirement for demonstrable dependency provenance.
Migration path
Do not add the archived repository as a Composer dependency from Packagist. Three viable paths, in order of preference:
get/first/paginate/count in Cache::tags([$table])->remember($key, $ttl, $callback), and flushes the tag in saved/deleted model events. Owning ~200 lines of code is strictly cheaper than owning an unmaintained dependency, and it lets you bake in tenant scoping and observability from day one.app/Support/Cacheable or an internal Composer package with a pinned namespace, add tests, and treat it as first-party code. Acceptable if the team wants the exact existing semantics.genealabs/laravel-model-caching occupies the same design space with active maintenance; spatie/laravel-responsecache solves the HTTP-layer variant if the real goal is response latency rather than model-level reuse. Evaluate either against the same correctness checklist.For an existing deployment already using the package: freeze the version, pin it in composer.json with an exact constraint, vendor it, and schedule replacement within one quarter. Do not carry it through the next major Laravel upgrade.
Compatibility
Verify before any pilot: exact Laravel constraint in composer.json against the target app version; PHP 8.2/8.3 deprecation surface; that newEloquentBuilder and newBaseQueryBuilder overrides do not conflict with any other package already extending the builder (common collision with soft-delete extensions, audit-log packages, and search integrations); that the cache store supports tags in all environments; and that global scopes (tenancy, soft deletes) are reflected in the cache key.
Sequencing
Maintenance
The upstream maintenance cost is zero and will stay zero — the repository is archived. All maintenance is transferred to your team the moment it ships. Practically that means: revalidating the builder overrides against every Laravel minor, owning any security response, and owning documentation so that "why is this read stale" is answerable by an on-call engineer at 3am. Budget roughly 1–2 engineer-days per Laravel major upgrade for revalidation, plus ongoing review overhead enforcing the convention that models must not be bypassed.
Support
No vendor, no maintainer, no issue tracker, no security contact. Internal support depends entirely on whether the pattern is understood by more than one person. Mitigate by keeping the surface small (prefer internal reimplementation over vendoring the full package), documenting the invalidation contract in the repo, and adding a runbook entry: "stale data suspected → flush tag {table} → confirm."
Scaling
Read scaling is the point: offloading repeated queries to Redis reduces primary DB load roughly in proportion to hit rate, and tag-based invalidation scales acceptably because flushes are per-table rather than global. Watch three things: (1) cache stampede on TTL expiry for hot keys — the package does not implement locking, so a cold tag under high concurrency can produce a thundering herd against the DB; mitigate with jittered TTLs or a lock wrapper. (2) Redis memory growth from large result sets — cache keys hash the full SQL, so highly variable filter combinations produce a combinatorial key space; enforce bounded filter surfaces and TTLs. (3) Tag flush cost — flushing a busy table's tag invalidates everything for that table, so write-heavy tables will see low effective hit rates and add churn without benefit.
Failure modes
array and fail in production only if the driver differs.Ramp-up
Low to get running (hours), moderate to operate safely (weeks). Engineers need to internalise three things: which models are cached, what the invalidation contract is, and that any write not going through Eloquent breaks the guarantee. A single 60-minute walkthrough plus a repo-level ADR covering the failure modes above is sufficient onboarding for a mid-level team.
Recommendation: do not adopt the archived package as a dependency. Either reimplement the ~200-line pattern internally with tenant scoping and metrics baked in, or evaluate genealabs/laravel-model-caching against the same correctness harness. Treat implicit model-level caching as an optimisation to be earned by measurement, not a default.
How can I help you explore Laravel packages today?