Everything the package exports. Start with withCache; the rest is
for custom handler files, operations and the legacy data cache API. Behaviour (outages, tag
coordination) is described in How it works, and the key layout in
Redis Configuration.
| Export | Kind | Purpose |
|---|---|---|
withCache(nextConfig, options?) |
function | Configures the whole cache. Below. |
createPageCacheHandler(options?) |
function → class | The page handler with code-level options, for a custom cacheHandler file. |
RedisCacheHandler |
class | The page handler. Same constructor as 16.4.2, so subclasses still work. |
createRemoteCacheHandler(options?) |
function → DataCacheHandler |
Redis data handler plus memory fallback, for "use cache: remote". |
createLocalCacheHandler(options?) |
function → DataCacheHandler |
Memory data handler with shared tag invalidation, for "use cache". |
flushCache(options?) |
async function | Deletes this app's keys. Flushing. |
closeCache() |
async function | Closes the package's Redis connections so a test run or script can exit. Closing. |
setCacheLogger(logger) |
function | Sends the package's log lines to your logger. Logging. |
attachElastiCacheIamAuth(client, options?) |
function | Keeps your own Redis or Cluster authenticated to ElastiCache with refreshed IAM tokens. Below. |
createCacheHandler({ type }) |
function → DataCacheHandler |
Deprecated: the original data handler factory (legacy data cache API). |
createRedisDataCacheHandler, createMemoryDataCacheHandler, createIoredisAdapter |
functions | Deprecated: the original building blocks behind createCacheHandler. |
CacheOptions, CacheLogger, ElastiCacheIamOptions, WithCacheOptions, FlushCacheOptions, FlushCacheResult, PageCacheHandlerOptions, RemoteCacheHandlerOptions, LocalCacheHandlerOptions, DataCacheHandler, DataCacheEntry, PageCache* |
types |
The deprecated exports are still exported.
function withCache<T extends object>(
nextConfig: T,
options?: WithCacheOptions,
): T & WithCacheConfig;
function withCache<T extends object>(
nextConfig: (phase: string, context: { defaultConfig: object }) => T | Promise<T>,
options?: WithCacheOptions,
): (phase: string, context: { defaultConfig: object }) => Promise<T & WithCacheConfig>;
interface WithCacheOptions {
/** Set cacheHandler and cacheMaxMemorySize: 0. @default true */
pages?: boolean;
/** Storage for plain "use cache": "redis" shares values across instances. @default "memory" */
useCache?: "memory" | "redis";
/** Your own handler files. Relative paths resolve against process.cwd(). */
handlers?: { page?: string; default?: string; remote?: string };
/**
* In-process cache budget: heapPercent of the V8 heap limit, or maxMiB (wins).
* Wins over CACHE_MEMORY_HEAP_PERCENT / CACHE_MEMORY_MAX_MIB. @default { heapPercent: 10 }
*/
memory?: { heapPercent?: number; maxMiB?: number };
}"use cache" always goes to cacheHandlers.default and "use cache: remote" to
cacheHandlers.remote, as Next routes them; "use cache: private" never reaches a handler.
withCache does not check which flag turned "use cache" on, so cacheComponents: true and
Next's deprecated experimental.useCache: true both work.
Returns nextConfig plus:
| Key | Value |
|---|---|
cacheHandler |
handlers.page, or the built-in page handler. Omitted with pages: false. |
cacheHandlers.remote |
handlers.remote, or the built-in remote handler. |
cacheHandlers.default |
handlers.default, or the built-in local handler (memory), or with useCache: "redis" the built-in remote handler, which falls back to memory without Redis. |
cacheMaxMemorySize |
0, unless nextConfig sets it: then that value is kept, with a warning if it is not 0 (it has no effect once withCache sets the handlers). Omitted with pages: false. |
Throws if nextConfig already sets cacheHandlers, or cacheHandler unless pages: false
(then yours is kept), and if memory has a heapPercent outside (0, 100), a maxMiB that is
not a finite number above 0, a useCache other than "memory" or "redis", or any other key. memory adds no key to the config: it is handed to the handlers
through the environment of the process that loaded next.config (next dev, next start), so a
standalone server.js does not see it; withCache warns when output: "standalone" is set with it.
See Memory. A config function is wrapped
in an async one that applies the same settings to its result.
The built-in handlers read the environment at runtime.
Shared by every factory below and by flushCache. Each defaults to the environment, so a factory
called with no options behaves like the built-in handler. The table form, with notes, is in
Custom handlers.
interface CacheOptions {
/** @default REDIS_URL ?? VALKEY_URL ?? the ELASTICACHE_* env; unset → memory only */
url?: string;
/** Your own ioredis Redis or Cluster. Overrides url. Never closed or reconfigured. */
client?: Redis | Cluster;
/** @default CACHE_KEY_PREFIX ?? "nextjs:" */
keyPrefix?: string;
/** Serve from memory (each entry at most 60 s) while Redis is down. @default true */
memoryFallback?: boolean;
/**
* Per-command timeout in ms. On a client you pass in, it bounds the package's own commands
* through a proxy; 3 timeouts in a row → memory for 2 s. @default 1000
*/
commandTimeout?: number;
/**
* Ms to wait for a connection the package opens. Not used with client.
* @default 2000 (10000 with the ELASTICACHE_* host form)
*/
connectTimeout?: number;
/** Ms a pending command may wait for a reply before an owned connection is reopened. @default 2000 */
socketTimeout?: number;
/** Timeouts in a row that reopen an owned connection, or send a passed client to memory for 2 s. @default 3 */
maxConsecutiveTimeouts?: number;
/**
* ElastiCache IAM authentication for the connection the package opens: { userId, cacheName,
* region, serverless, credentials }, each defaulting to the ELASTICACHE_* / AWS_REGION env.
* Throws with client. @default IAM when ELASTICACHE_IAM_USER is set
*/
iam?: ElastiCacheIamOptions;
/** @default CACHE_DEBUG is `1` or `true` */
debug?: boolean;
/** Where this handler's warnings, errors and debug lines go. @default setCacheLogger's, else the console */
logger?: CacheLogger;
}Handlers in one process with the same connection and keyPrefix share one connection, one tag
store and one set of memory stores. CACHE_REDIS=off and next build force memory regardless of
these options. Different timeouts for the same server open a second connection, and the package
logs a warning when that happens, so give every handler the same settings.
function createPageCacheHandler(options?: PageCacheHandlerOptions): typeof RedisCacheHandler;Returns a RedisCacheHandler subclass with options applied. Export it as the default of a
custom cacheHandler file:
// cache/page.mjs
import { createPageCacheHandler } from "@mrjasonroy/cache-components-cache-handler";
import { client } from "./redis.mjs";
export default createPageCacheHandler({ client });The class Next constructs for the singular cacheHandler. It implements get, set,
revalidateTag, resetRequestCache, delete and close. get reads the entry and the tag
records that apply to it in one round trip (1 GET + 1 HMGET of the <prefix>tags hash), so a
revalidation on any instance is seen by the next read. The first read of an entry by a process
that did not write it takes one more HMGET, for the tags it learns from the entry. See
Sizing.
PageCacheHandlerOptions (16.4.2's RedisCacheHandlerOptions, still exported as a deprecated
alias until 16.5) is Next's constructor context plus CacheOptions and:
| Option | Default | Meaning |
|---|---|---|
buildId |
the app's deployment ID if set, else its BUILD_ID |
The build that scopes entry keys. |
defaultTTL |
31536000 (365 days) |
Lifetime in seconds of an entry with neither revalidate nor expire, at most 365 days. |
redis |
— | Deprecated (removed in 16.5): the 16.4.2 form of client / url, an ioredis client, a URL or an ioredis options object. Use client or url. |
tagPrefix |
— | Deprecated and ignored. Tag records live in the <keyPrefix>tags hash. |
The constructor has the same shape as in 16.4.2, so subclasses keep working. close() is deprecated:
it is the same as closeCache().
Both return a Next DataCacheHandler (get, set, refreshTags, getExpiration,
updateTags). Export the result as the default of a cacheHandlers file.
For "use cache: remote". Entries are stored in
Redis under <prefix><buildId>:data:<key> until their expire, with the memory fallback during
an outage. Takes CacheOptions plus buildId and defaultTTL: the seconds to keep an entry whose
expire is infinite (default 86400, 24 hours; anything but a finite number greater than 0 throws when the
handler is created). Every entry is kept at most 365 days.
For "use cache". Values live in this process's memory until their revalidate period: up to
10,000 entries and 32/98 of the memory budget (about 27 MiB at
--max-old-space-size=768 on Node 22). A larger value is not kept. When Redis is configured,
tag invalidations are shared across instances. Takes CacheOptions; only the connection,
keyPrefix, debug and logger matter.
// cache/default.mjs
import { createLocalCacheHandler } from "@mrjasonroy/cache-components-cache-handler";
import { client } from "./redis.mjs";
export default createLocalCacheHandler({ client });function flushCache(options?: FlushCacheOptions): Promise<FlushCacheResult>;
interface FlushCacheOptions extends CacheOptions {
/** "build": <prefix><buildId>:*. "all": every key under the prefix. @default "build" */
scope?: "build" | "all";
/** @default the app's deployment ID if set, else its BUILD_ID */
buildId?: string;
}
interface FlushCacheResult {
/** Redis keys deleted; without Redis, in-process entries dropped. */
deleted: number;
/** Set when some matching keys could not be deleted (a Cluster slot migration). Run it again. */
partial?: true;
/** How many matching keys could not be deleted; set with partial. */
failed?: number;
}Deletes with SCAN + UNLINK on every master of a Cluster, and empties this process's memory stores.
deleted is the number of Redis keys deleted, or, without Redis, the number of memory entries
dropped. It throws, deleting nothing, if Redis is configured but unavailable, or for
scope: "all" with an empty keyPrefix. It also throws if a Redis node stops answering
(commandTimeout, also on each Cluster master) or refuses part-way: some keys may already be
deleted, so run it again. After the delete it writes a tag record for the flush
(__cch_flush__, or __cch_flush__:<buildId> for scope: "build") that prerendered build output
is checked against, so build output older than the flush is not served again. See
Flushing the cache.
function closeCache(): Promise<void>;For test runs, scripts and CLIs, so Node can exit; a Next server never needs it. Closes every
Redis connection the package opened in this process and empties its memory stores. A client
you passed in is never closed. It never rejects because Redis is down, and is safe to call more
than once. Handlers created before it reconnect on their next call. The details, including what
happens to revalidations in flight, are under Closing the cache.
import { afterAll } from "vitest";
import { closeCache } from "@mrjasonroy/cache-components-cache-handler";
afterAll(() => closeCache());interface CacheLogger {
error(message: string, meta?: Record<string, unknown>): void;
warn(message: string, meta?: Record<string, unknown>): void;
info?(message: string, meta?: Record<string, unknown>): void;
debug?(message: string, meta?: Record<string, unknown>): void;
}
function setCacheLogger(logger: CacheLogger | undefined): void;Sends the package's warnings, errors and CACHE_DEBUG lines to logger for the whole process
(every module graph), or back to the console with undefined. Call it in instrumentation.ts's
register() or a custom handler file. The logger option of createRemoteCacheHandler,
createLocalCacheHandler and createPageCacheHandler wins over it for that handler; the shared
connection and tag state use the logger of the handler that opened them. message is what the
console would print; meta holds the details (error, operation). Without info or debug
those lines are dropped. Errors stay rate-limited. No line carries a Redis URL or connection
options; errors, their causes, objects and URLs are scrubbed of credentials, but other free text in
a message is not. A logger that throws never fails a cache call: the line goes to the console.
function attachElastiCacheIamAuth(
client: Redis | Cluster,
options?: ElastiCacheIamOptions & { logger?: CacheLogger },
): { refresh(): Promise<boolean>; stop(): void };For a client you build yourself, such as a Cluster for cluster-mode-enabled ElastiCache.
Create the client with lazyConnect: true and TLS, and do not connect it. Then this:
- connects it once the first IAM token is in its options;
- makes a new token every 10 minutes, puts it in the options for reconnects (every node's options
on a
Cluster) and sendsAUTHwith it on every connected node.
Options left out come from the environment, as in
IAM authentication. Throws when IAM cannot work (TLS off, no
user, cache name or region) or the AWS packages are not installed. refresh() makes a new token
now; stop() ends the refresh and leaves the client connected. Call it once per client:
IAM on your own client has the full handler-file example.
The data cache API of 16.4.2 and earlier. Deprecated in 16.4.3: it keeps working in 16.4.x,
logs a one-time deprecation warning on first use, and is removed in 16.5. Use withCache, or
createRemoteCacheHandler / createLocalCacheHandler. createCacheHandler keeps its own key
layout (nextjs:data-cache:, nextjs:tags:) and covers "use cache" only, not pages.
// data-cache-handler.mjs
import { createCacheHandler } from "@mrjasonroy/cache-components-cache-handler";
export default createCacheHandler({ type: process.env.REDIS_URL ? "redis" : "memory" });type is "memory", "redis", "valkey" or "elasticache". The Redis types share the process's
connection, fall back to memory during an outage, and use memory during next build and with
CACHE_REDIS=off.
The 16.4.2 wiring still works: a handler file that exports createCacheHandler({ type }), wired
with createCacheConfig or by hand into cacheHandlers. In production it logs a one-time
reminder to use withCache; pass suppressIsrWarning: true to silence it.
createCacheHandler reads REDIS_URL / VALKEY_URL, REDIS_PASSWORD and the ELASTICACHE_*
variables, and honours CACHE_REDIS=off and the build phase. It does not read CACHE_KEY_PREFIX
or CACHE_DEBUG. Its options:
| Option | Default | What it does |
|---|---|---|
url |
REDIS_URL / VALKEY_URL, else redis://localhost:6379 |
Connection URL (redis, valkey) |
endpoint / port |
ELASTICACHE_ENDPOINT / ELASTICACHE_PORT, 6379 |
Host and port (elasticache) |
tls |
true for elasticache, else false |
Use TLS |
password |
ELASTICACHE_AUTH_TOKEN / REDIS_PASSWORD |
Auth token or password |
client |
— | Your own ioredis Redis or Cluster; you own its lifecycle |
keyPrefix / tagPrefix |
"nextjs:data-cache:" / "nextjs:tags:" |
Key prefixes |
commandTimeout |
1000 (ms) |
Per-command timeout |
connectTimeout |
2000 (ms; 10000 for elasticache) |
Connect timeout |
socketTimeout |
2000 (ms) |
Drop the connection when a pending command gets no reply for this long |
maxConsecutiveTimeouts |
3 |
Timeouts in a row before the connection is dropped and redialled (with client: before it is marked not ready for 2 s) |
memoryFallback / fallbackTTL |
true / 60 (s) |
Serve from memory during an outage, each entry for at most fallbackTTL |
defaultTTL |
86400 (s) |
TTL for entries without a finite expire |
tagTTL |
31622400 (s, 366 days) |
TTL for tag records; entry TTLs are capped at it |
errorLogIntervalMs |
60000 |
Redis errors are logged at most once per operation per interval |
suppressIsrWarning |
false |
Silence the one-time production reminder |
maxSize |
100 MB | Memory budget (memory) |
debug |
false |
Debug logging |
A memory data handler. Options: maxSize in bytes (default 50 MB) and debug.
The Redis data handler behind createCacheHandler, without the shared connection or the
fallback. Options: redis (a node-redis-style client, required), keyPrefix
("nextjs:data-cache:"), tagPrefix ("nextjs:tags:"), defaultTTL (86400), tagTTL
(366 days), errorLogIntervalMs (60000) and debug.
Wraps an ioredis Redis or Cluster so createRedisDataCacheHandler can use it. It translates
node-redis SET options ({ EX: seconds }) to ioredis positional arguments. Without it, Redis
rejects writes with ERR syntax error. The new handlers take ioredis directly and don't need it.
import Redis from "ioredis";
import {
createIoredisAdapter,
createRedisDataCacheHandler,
} from "@mrjasonroy/cache-components-cache-handler";
export default createRedisDataCacheHandler({
redis: createIoredisAdapter(new Redis(process.env.REDIS_URL)),
});Deprecated in 16.4.3, with JSDoc pointing at the replacement. They keep working in 16.4.x and log a one-time deprecation warning (once per process, per API) on first use. They are removed in 16.5.
| Deprecated | Use instead | Why |
|---|---|---|
createCacheHandler |
withCache, or createRemoteCacheHandler / createLocalCacheHandler in a custom handler |
The original data stack: "use cache" only, its own key layout, and no page handler. It does not reconnect after closeCache(): create it again. |
createRedisDataCacheHandler, createIoredisAdapter |
createRemoteCacheHandler({ client }) |
It takes an ioredis client directly; no adapter. |
createMemoryDataCacheHandler |
createLocalCacheHandler |
Memory with tag invalidation shared across instances. |
RedisCacheHandler#close() |
closeCache() |
The same, without needing a handler. |
The page handler's redis and tagPrefix options, and a defaultTTL that is not a number |
client or url; nothing for tagPrefix; a number of seconds |
16.4.2 forms. tagPrefix is ignored: tag records live in the <keyPrefix>tags hash. |
RedisCacheHandlerOptions |
PageCacheHandlerOptions |
Renamed with createPageCacheHandler; the same type. |
createCacheConfig, createCacheConfigWithProfiles |
withCache |
Both make you write and wire handler files yourself. |
CompositeHandler, createCompositeHandler |
built in | The memory fallback is now inside every handler. |
MemoryCacheHandler, createMemoryCacheHandler |
withCache without REDIS_URL |
Memory only is the no-URL mode. |
bufferToString, stringToBuffer, jsonReplacer, jsonReviver, isImplicitTag, calculateLifespan, isExpired, IMPLICIT_TAG_PREFIX, and the Next 14 CacheHandler* / CacheValue / LifespanParameters types |
none | Internals of the Next 14 handlers. |
RedisCacheHandler is not deprecated. It is the page handler withCache uses.
Use withCache. They return { cacheHandlers, cacheMaxMemorySize } for handler files you write
yourself:
createCacheConfig({ dataCacheHandlerPath, isrHandlerPath?, disableDefaultMemoryCache? })pointsdefaultandremoteat one file.createCacheConfigWithProfiles({ defaultDataCacheHandlerPath, remoteDataCacheHandlerPath, isrHandlerPath?, disableDefaultMemoryCache? })takes one file per profile.
isrHandlerPath is passed through as cacheHandler. disableDefaultMemoryCache defaults to
true (cacheMaxMemorySize: 0).
MemoryCacheHandler, createMemoryCacheHandler, CompositeHandler, createCompositeHandler,
bufferToString, stringToBuffer, jsonReplacer, jsonReviver, isImplicitTag,
calculateLifespan, isExpired, IMPLICIT_TAG_PREFIX, and the types CacheHandler,
CacheHandlerContext, CacheHandlerGetMeta, CacheHandlerOptions, CacheHandlerValue,
CacheValue and LifespanParameters. See the Deprecated table above for
replacements.
WithCacheOptions, WithCacheConfig, NextConfigFunction, MemoryOptions, CacheOptions,
ElastiCacheIamOptions,
AttachElastiCacheIamAuthOptions, ElastiCacheIamAuth, AwsCredentials,
AwsCredentialsProvider, PageCacheHandlerOptions, RedisCacheHandlerOptions (deprecated),
RemoteCacheHandlerOptions, LocalCacheHandlerOptions, FlushCacheOptions, FlushCacheResult,
PageCacheControl, PageCacheGetContext, PageCacheHandlerContext, PageCacheHandlerValue,
PageCacheSetContext, PageCacheValue, DataCacheHandler, DataCacheEntry, Timestamp.
Types of the deprecated legacy data cache API, removed with it in 16.5:
DataCacheHandlerOptions, CacheHandlerType, MemoryDataCacheHandlerOptions,
RedisDataCacheHandlerOptions, RedisClient, IoredisLike, CacheHandlerConfig.
The package sits behind Next's own caching APIs: "use cache", "use cache: remote"
("use cache: private" never reaches it),
cacheLife, cacheTag, revalidateTag, updateTag and revalidatePath. See
Usage Examples and Next's
Caching and Revalidating.