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

Eloquent Redis Mirror Laravel Package

petkakahin/eloquent-redis-mirror

A Laravel package that mirrors Eloquent models into Redis, keeping cached copies in sync on save and delete so you can serve fast reads without touching the database. Drop-in setup that leaves your existing Eloquent workflow unchanged.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. Eloquent Redis Mirror is a transparent read-through/write-through cache bound to Eloquent model events. It fits Laravel services that are read-heavy, have a small number of hot models (catalogue, project/task, profile-style aggregates), and — critically — are the only writer to those tables. It is a poor fit for any domain where the database is written by anything other than the instrumented Eloquent models: bulk Model::where(...)->update(), insert()/upsert(), raw SQL, reporting jobs, admin tools, ETL, or a second service sharing the schema. In those cases Redis becomes silently divergent from the database and the "source of truth is always the database" claim holds only at the storage layer, not at the read layer the application sees.

Integration feasibility. Integration cost is genuinely low: one composer require, one trait, one $redisRelations array, no changes to calling code. That is attractive for a pilot. The real effort is not the code change but the governance change: enumerating every write path to the affected tables, deciding which models are safe to mirror, and sizing Redis. composer require is an afternoon; the coherence audit is a sprint.

Technical risk. Ranked:

  1. Event-bypass drift (high). Cache invalidation depends entirely on Eloquent model events. Any write that skips them leaves stale Redis state, bounded only by the 24h warmed-flag TTL — which is a flag lifetime, not a documented data TTL. This is the dominant risk and drives most of the design constraints.
  2. Transaction semantics (high). Model events fire inside a DB transaction. A rollback after create/update appears to leave Redis populated with rows that never committed. Release notes do not mention afterCommit handling. This must be verified in a spike before any production use.
  3. Partial query coverage (medium-high). find/findMany/with/first/paginate/exists are listed, but the boundaries of where() support are unstated. A cache that transparently serves some query shapes and not others is a footgun: developers cannot reason locally about freshness, and behaviour changes silently as queries are refactored.
  4. Redis role collision (medium). Mirroring duplicates tables plus sorted-set indices plus pivot keys into Redis and needs a defined maxmemory-policy. If the mirror shares an instance with queues, sessions, or locks, allkeys-lru will evict job payloads under memory pressure. A dedicated connection and, preferably, a dedicated instance is a hard prerequisite, not a nicety.
  5. Vendor/maintainer risk (medium). v1.0.0, single-author namespace, no stated licence, security policy, support window, or semver commitment. 324 tests and PHPStan level max are strong quality signals for a first release, but they are the author's tests, not an ecosystem track record. Bus factor is 1.
  6. Fail-open behaviour (medium). Falling back to the database is the correct default, but on a cold cache or a Redis failover every read in the fleet hits the database simultaneously. The package makes the failure graceful but not cheap; the thundering-herd profile needs to be modelled against database connection limits.

Key questions. (a) Are writes to mirror-target tables exclusively through the instrumented models, in every environment including admin and batch? (b) Are Redis writes deferred to transaction commit, and what happens on rollback? (c) Exactly which query constraints and relation shapes are served from Redis versus passed through, and is there an observability hook to tell which happened? (d) Does key naming support tenant isolation and safe flush-by-namespace? (e) What is the actual data TTL versus the 24h warmed flag? (f) Memory footprint per million mirrored rows, and target eviction policy? (g) Licence, security disclosure process, and maintainer's stated support/backwards-compatibility policy? (h) Is there a supported way to invalidate or rebuild the entire mirror (an operational kill switch)?

Integration Approach

Stack fit. Requires PHP 8.2+ and Laravel 11+. That is a clean fit for services already modernised and a hard blocker for anything on Laravel 10 or PHP 8.1 — those would need a framework upgrade first, which is a separate project and should not be bundled into a caching initiative. The trait-based, opt-in design is the package's biggest strategic advantage: it is removable. Adoption does not restructure the domain model, so a reversal is a code revert plus a Redis flush rather than a data migration.

Migration path. No data migration is required — the mirror is derived state, rebuildable from the database via lazy warm-up. That keeps the rollback story simple and is the main reason to prefer this package over anything requiring a schema or dual-write change. The migration is therefore purely additive: new dependency, new trait on selected models, new Redis connection config.

Compatibility. Three compatibility surfaces must be confirmed rather than assumed. First, framework: Laravel 11+ only; confirm no transitive constraint conflicts with existing packages. Second, write-path: any package or internal module that mutates the target tables outside the trait-instrumented models is a coherence hole — audit before, not after. Third, custom relations: third-party relation types (belongsToSortedMany and similar) require explicit $redisCustomRelations mapping and withRedisContext(); unlisted custom relations likely fall back to the database rather than failing loudly, which is safe but means "we cache this relation" may be untrue in practice.

Sequencing. (1) Provision a dedicated Redis connection (separate instance or at minimum separate logical DB) with an explicit non-allkeys-lru eviction policy and memory headroom sized from production row counts. (2) Write-path audit of the candidate model's tables; anything with unknown writers is disqualified from the pilot. (3) Spike the two unresolved correctness questions — transaction rollback and where() coverage — in a throwaway branch. (4) Pilot on a single read-heavy, low-blast-radius model, ideally one where stale reads degrade an experience rather than corrupt a decision. (5) Run a measurement window comparing Redis-served and database-served results for the same queries, or at minimum instrument cache hit ratio and fallback rate. (6) Only then extend trait coverage model by model. Do not enable it on money, entitlement, or inventory-path models until the audit and the spike have both cleared.

Operational Impact

Maintenance. Steady-state maintenance is modest but non-zero and concentrated in exactly one place: keeping the write-path audit current. Every new migration, artisan command, import job, or service that touches a mirrored table is a potential coherence break, and that discipline erodes silently over time. Budget for a periodic reconciliation check (sampled comparison of Redis mirror against the database) as a permanent control, not a one-off. Upgrades carry normal semver risk against a v1.0.0 single-maintainer package: pin the version, review changelogs, and keep the trait behind a small internal wrapper so the dependency can be swapped without touching domain code.

Support. No commercial support and an unknown maintainer response profile. Internal capability is the real support line: someone on the team must be able to read the package's event handlers and explain invalidation behaviour, or the service becomes an operational black box. That is a genuine ramp-up cost and should be staffed deliberately — a named owner, not "the team". Add a fallback to the trivial alternative (Laravel's own cache with explicit invalidation) if the package turns out to be unmaintained; the trait design makes that exit cheap.

Scaling. Reads scale well — that is the point, and offloading hot find/with/exists traffic to Redis should be measurable. Two scaling constraints apply. Memory scales with mirrored rows times the number of cached representations (entity keys, sorted-set indices, pivot keys), so growth is superlinear relative to table growth and needs monitoring, not just provisioning. And Redis becomes a latency-critical dependency on the read path: failure is graceful, but recovery is a database-wide traffic spike. Size the database for the failover case, and warm the cache deliberately after deploys or restarts rather than relying purely on lazy cold start for high-traffic models.

Failure modes. Ranked by expected pain: (1) silent staleness from an event-bypassing write — no error, no alert, wrong data shown, discovered by a user; the worst class of failure because it is invisible to monitoring. (2) phantom reads from transaction rollback if afterCommit is not honoured — data visible in the UI that does not exist. (3) eviction of unrelated Redis data if the mirror shares an instance with queues or sessions under allkeys-lru. (4) thundering herd on Redis outage or cold start, presenting as a database incident rather than a cache incident — this misdiagnosis will cost time in the first real outage. (5) memory exhaustion and key explosion as mirrored relations multiply. (6) partial-coverage surprise, where a refactored query silently stops being cached and a previously fine latency profile degrades.

Ramp-up. Individual developer onboarding is close to zero — the API is unchanged, which is the package's strongest selling point. Organisational ramp-up is the real cost: the team must internalise a new rule ("all writes to mirrored tables go through Eloquent models, and here is why") and a new diagnostic reflex ("is this Redis or the database?"). Both need documentation and at least one runbook covering flush-and-rebuild, fallback verification, and how to check whether a given query was served from cache. Without that, the package will be adopted enthusiastically by feature teams and understood by nobody during the first incident.

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.
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log