Undici ships a cache interceptor that stores HTTP responses and serves them from local storage on subsequent requests, eliminating unnecessary round-trips. The interceptor is fully RFC 9111-compliant: it respectsDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/nodejs/undici/llms.txt
Use this file to discover all available pages before exploring further.
Cache-Control directives, validates stale responses via ETag and Last-Modified, and implements stale-while-revalidate for background refreshes. Two pre-built stores are available — an in-memory store suitable for most applications and a SQLite-backed store for durable, persistent caching across process restarts.
Enabling the cache interceptor
Attach the cache interceptor to anAgent (or any dispatcher) using the compose helper:
Cache interceptor with default MemoryCacheStore
request() and fetch() calls benefit from caching:
Global caching via setGlobalDispatcher
Cache interceptor options
| Option | Type | Default | Description |
|---|---|---|---|
store | CacheStore | new MemoryCacheStore() | The storage backend to use |
methods | string[] | ['GET'] | HTTP methods to cache |
type | 'shared' | 'private' | 'shared' | Whether this is a shared or private cache |
cacheByDefault | number | undefined | Default TTL in seconds for responses without Cache-Control |
origins | (string | RegExp)[] | undefined | Allowlist of origins to cache; all others are bypassed |
MemoryCacheStore
The default store keeps all cached responses in a JavaScript Map in the current process. It is zero-dependency and suitable for applications where cache persistence across restarts is not required.
Options
| Option | Type | Default | Description |
|---|---|---|---|
maxSize | number | 104857600 (100 MB) | Maximum total size in bytes of all cached responses |
maxCount | number | 1024 | Maximum number of cached responses |
maxEntrySize | number | 5242880 (5 MB) | Maximum body size in bytes for a single entry; larger bodies are not cached |
Configuring MemoryCacheStore
maxSize or maxCount, the store evicts approximately half of the oldest entries and emits a 'maxSizeExceeded' event:
Listening to cache eviction
SqliteCacheStore
The SQLite store persists responses to a database file, surviving process restarts. It uses Node.js’s built-in node:sqlite module, which requires the --experimental-sqlite flag on Node.js versions before it becomes stable.
Running with experimental SQLite
Configuring SqliteCacheStore
| Option | Type | Default | Description |
|---|---|---|---|
location | string | ':memory:' | Path to the SQLite database file |
maxCount | number | Infinity | Maximum number of entries |
maxEntrySize | number | Infinity | Maximum body size in bytes per entry |
When to use memory vs SQLite
MemoryCacheStore
Best for ephemeral caching in short-lived processes, CI environments, or when you want zero dependencies and maximum speed. Cache is lost when the process exits.
SqliteCacheStore
Best for long-running servers that benefit from warm caches across restarts, or for CLI tools that make repeated requests to the same endpoints.
Cache-Control header support
The interceptor fully respectsCache-Control directives on both requests and responses.
Response directives
| Directive | Behaviour |
|---|---|
max-age=N | Cache the response for N seconds |
no-cache | Always revalidate before serving the cached response |
no-store | Never cache this response |
stale-while-revalidate=N | Serve stale response immediately and revalidate in the background within N seconds of becoming stale |
stale-if-error=N | Serve a stale response if the origin returns an error, within N seconds of becoming stale |
Request directives
| Directive | Behaviour |
|---|---|
no-cache | Force revalidation regardless of freshness |
no-store | Bypass cache entirely for this request |
max-age=N | Refuse responses older than N seconds |
max-stale=N | Accept stale responses up to N seconds past expiry |
min-fresh=N | Only accept responses with at least N seconds of freshness remaining |
only-if-cached | Only return a cached response; return 504 Gateway Timeout if none exists |
ETag and Last-Modified validation
When a cached response becomes stale, the interceptor automatically sends a conditional request to revalidate it:- ETag: adds an
If-None-Matchheader with the storedETagvalue - Last-Modified: adds an
If-Modified-Sinceheader with the cached date
304 Not Modified, the cached entry is refreshed in-place without transferring the body again.
Server response that triggers revalidation
Configuring which methods to cache
By default onlyGET requests are cached. To also cache HEAD requests:
Caching GET and HEAD
Only safe HTTP methods (those without side effects) should be cached. Do not add
POST, PUT, PATCH, or DELETE to the methods array.Restricting caching to specific origins
Use theorigins option to limit caching to a set of trusted origins:
Origin allowlist
Caching responses without Cache-Control
Some APIs do not set Cache-Control. Use cacheByDefault to assign a default TTL in seconds for these responses:
Default TTL for uncacheable responses
Writing a custom cache store
Implement theCacheStore interface if you need a different backend (Redis, Memcached, etc.):
Custom cache store interface