@appelboomhd/nextjs-redis-sentinel-cache-handler
v0.3.0
Published
Next.js cache handler backed by ioredis with Redis Sentinel support.
Downloads
511
Maintainers
Readme
@appelboomhd/nextjs-redis-sentinel-cache-handler
Next.js cache handler backed by ioredis, with support for Redis Sentinel, direct Redis connections, tag revalidation, replica reads, an in-memory LRU tier for hot entries, and a filesystem fallback when Redis is unavailable.
Features
- Redis Sentinel support for master/replica setups
- Direct Redis mode for simpler deployments
- Filesystem fallback when Redis is unavailable
- Tag-based invalidation via
revalidateTag() - Circuit breaker to avoid repeated failures during Redis outages
- In-memory LRU tier that serves hot entries without a Redis round-trip
Install
npm install @appelboomhd/nextjs-redis-sentinel-cache-handler ioredisnext is a peer dependency and is expected to already be present in your Next.js app.
Usage
Configure your Next.js app to use the package as its cache handler:
// next.config.js
module.exports = {
cacheHandler: require.resolve('@appelboomhd/nextjs-redis-sentinel-cache-handler'),
cacheMaxMemorySize: 0,
}Configuration
Sentinel mode
REDIS_SENTINEL_URL=redis://sentinel-1:26379,redis://sentinel-2:26379,redis://sentinel-3:26379
REDIS_SENTINEL_MASTER_NAME=myprimary
REDIS_PASSWORD=your-password
REDIS_DB=0
REDIS_CACHE_PREFIX=cache:
REDIS_CACHE_DEBUG_LEVEL=0
REDIS_ENABLE_AUTOPIPELINING=0Direct Redis mode
REDIS_URL=redis://redis-host:6379
REDIS_PASSWORD=your-password
REDIS_DB=0
REDIS_CACHE_PREFIX=cache:
REDIS_CACHE_DEBUG_LEVEL=0Environment variables
| Variable | Required | Description |
| ----------------------------- | ------------- | -------------------------------------------------------- |
| REDIS_SENTINEL_URL | Sentinel mode | Comma-separated Redis Sentinel URLs. |
| REDIS_SENTINEL_MASTER_NAME | No | Sentinel master name. Defaults to myprimary. |
| REDIS_URL | Direct mode | Direct Redis connection URL. |
| REDIS_PASSWORD | No | Password used for Redis and Sentinel. |
| REDIS_DB | No | Database index. Defaults to 0. |
| REDIS_CACHE_PREFIX | No | Key prefix. Defaults to cache:. |
| REDIS_CACHE_DEBUG_LEVEL | No | 0 = silent, 1 = errors, 2 = warnings, 3 = debug. |
| REDIS_ENABLE_AUTOPIPELINING | No | 1 = enabled. Defaults to disabled. |
| REDIS_CACHE_LRU_ENABLED | No | 0 = disabled. Defaults to enabled. |
| REDIS_CACHE_LRU_MAX | No | Max entries in the in-memory tier. Defaults to 1000. |
| REDIS_CACHE_LRU_MAX_SIZE | No | Approx. memory budget in bytes. Defaults to 50 MB. |
| REDIS_CACHE_LRU_TTL_MS | No | In-memory entry TTL in ms. Defaults to 5000. |
| REDIS_CACHE_BUILD_ID | No | Override the detected build ID. Defaults to .next/BUILD_ID. |
| REDIS_CACHE_FS_FALLBACK_ON_MISS | No | 0 = disabled. Defaults to enabled. |
| REDIS_CACHE_TTL_SECONDS | No | Baseline entry TTL in seconds. Defaults to 14 days. |
REDIS_DB selects the Redis logical database for both modes. In direct mode a database in the REDIS_URL path (redis://redis-host:6379/2) wins over it, so use one or the other.
Use either Sentinel mode or direct mode. If neither REDIS_SENTINEL_URL nor REDIS_URL is configured, the handler will fall back to the Next.js filesystem cache only.
Build-scoped keys
Every next build generates a new BUILD_ID, and prerendered HTML hardcodes /_next/static/<BUILD_ID>/... script tags. Because cache keys are scoped by route path, a shared Redis would otherwise hand a new deployment the HTML written by the previous one — script tags pointing at a static directory that no longer exists on disk, so _buildManifest.js and _ssgManifest.js 404 until the cache is flushed.
Entries are therefore namespaced per build:
<REDIS_CACHE_PREFIX>b:<buildId>:<cacheKey> entry
<REDIS_CACHE_PREFIX>b:<buildId>:tags:<tag> tag -> keys index
<REDIS_CACHE_PREFIX>tagtime:<tag> revalidation marker (shared)The build ID is read from <serverDistDir>/../BUILD_ID at startup, which ships inside output: 'standalone' and so can never drift from the HTML being served. Override with REDIS_CACHE_BUILD_ID. When no build ID can be resolved (for example next dev), keys stay unscoped and a warning is logged.
Tag revalidation markers are deliberately not build-scoped. During a rolling deployment both builds serve traffic, and a revalidateTag() issued by a pod on the old build must invalidate entries held by pods on the new one.
Superseded namespaces are not actively deleted; they expire via REDIS_CACHE_TTL_SECONDS. Since each build writes a complete fresh copy rather than overwriting the previous one, lower that value if Redis memory becomes a concern.
Filesystem fallback on miss
A build-scoped namespace starts empty on every deployment, and Next.js has no filesystem fallback of its own once a custom cacheHandler is configured. On a Redis miss the handler therefore reads the running build's prerendered output from disk, serves it, and back-fills Redis — preserving the original lastModified so the ISR clock is not reset. Entries whose tags have since been revalidated are skipped, so a revalidation cannot be undone by build-time output. Disable with REDIS_CACHE_FS_FALLBACK_ON_MISS=0.
In-memory LRU tier
Setting a custom cacheHandler disables Next.js's built-in in-memory ISR cache, so without this tier every request pays a Redis round-trip plus a full JSON deserialization — even for hot pages. The LRU tier restores a process-local fast path: entries are stored already deserialized, so a memory hit skips both the Redis read and the JSON.parse.
- Bounded by entry count (
REDIS_CACHE_LRU_MAX) and an approximate byte budget (REDIS_CACHE_LRU_MAX_SIZE). - Entries expire after a short TTL (
REDIS_CACHE_LRU_TTL_MS) so arevalidateTag()on another instance cannot keep a stale copy alive for long. - Memory hits still honor tag revalidation: stale entries are evicted locally and re-fetched through the Redis path.
- Disable it entirely with
REDIS_CACHE_LRU_ENABLED=0.
Development
npm install
npm run typecheck
npm run buildLicense
EUPL-1.2
