-
Couldn't load subscription status.
- Fork 29.7k
docs: cacheHandlers #85311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: canary
Are you sure you want to change the base?
docs: cacheHandlers #85311
Conversation
docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.mdx
Outdated
Show resolved
Hide resolved
| ```js filename="cache-handlers/external-handler.js" | ||
| module.exports = class ExternalCacheHandler { | ||
| async get(cacheKey, softTags) { | ||
| // Retrieve from external storage | ||
| const stored = await externalStorage.get(cacheKey) | ||
| if (!stored) { | ||
| return undefined | ||
| } | ||
|
|
||
| // Deserialize the entry | ||
| // Note: You'll need to reconstruct the ReadableStream from stored data | ||
| const entry = { | ||
| value: new ReadableStream({ | ||
| start(controller) { | ||
| controller.enqueue(stored.data) | ||
| controller.close() | ||
| }, | ||
| }), | ||
| tags: stored.tags, | ||
| stale: stored.stale, | ||
| timestamp: stored.timestamp, | ||
| expire: stored.expire, | ||
| revalidate: stored.revalidate, | ||
| } | ||
|
|
||
| return entry | ||
| } | ||
|
|
||
| async set(cacheKey, pendingEntry) { | ||
| const entry = await pendingEntry | ||
|
|
||
| // Read the stream to get the data | ||
| const reader = entry.value.getReader() | ||
| const chunks = [] | ||
|
|
||
| try { | ||
| while (true) { | ||
| const { done, value } = await reader.read() | ||
| if (done) break | ||
| chunks.push(value) | ||
| } | ||
| } finally { | ||
| reader.releaseLock() | ||
| } | ||
|
|
||
| // Combine chunks and store to external storage | ||
| const data = Buffer.concat(chunks.map((chunk) => Buffer.from(chunk))) | ||
|
|
||
| await externalStorage.set(cacheKey, { | ||
| data, | ||
| tags: entry.tags, | ||
| stale: entry.stale, | ||
| timestamp: entry.timestamp, | ||
| expire: entry.expire, | ||
| revalidate: entry.revalidate, | ||
| }) | ||
| } | ||
|
|
||
| async refreshTags() { | ||
| // Sync with external tag service if applicable | ||
| // await externalTagService.refresh() | ||
| } | ||
|
|
||
| async getExpiration(tags) { | ||
| // Query external service for tag expiration | ||
| // const expiration = await externalTagService.getExpiration(tags) | ||
| // return expiration | ||
| return 0 | ||
| } | ||
|
|
||
| async updateTags(tags, durations) { | ||
| // Update external tag service | ||
| // await externalTagService.updateTags(tags, durations) | ||
| } | ||
| } | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "External storage pattern" code example uses an undefined variable externalStorage without explaining that it's a placeholder. This could confuse developers trying to implement custom cache handlers.
View Details
📝 Patch Details
diff --git a/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.mdx b/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.mdx
index f3e153bfe3..7839362c11 100644
--- a/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.mdx
+++ b/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.mdx
@@ -258,6 +258,8 @@ module.exports = class MemoryCacheHandler {
For durable storage like Redis or a database, you'll need to serialize the cache entries:
```js filename="cache-handlers/external-handler.js"
+// Note: `externalStorage` should be replaced with your actual storage implementation
+// (e.g., Redis client, database connection, Memcached client, etc.)
module.exports = class ExternalCacheHandler {
async get(cacheKey, softTags) {
// Retrieve from external storage
Analysis
Undefined placeholder variable externalStorage not explained in documentation
What fails: The "External storage pattern" code example in cacheHandlers.mdx uses the undefined variable externalStorage.get() and externalStorage.set() without explaining that it's a placeholder that needs to be replaced with an actual implementation.
How to reproduce: Open docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.mdx and read the "External storage pattern" section (lines 260-335). The code shows:
const stored = await externalStorage.get(cacheKey)
// ...
await externalStorage.set(cacheKey, { ... })Result: Developers reading this example may not understand that externalStorage is a placeholder and must be replaced with their own storage client (Redis, Memcached, database, etc.), causing confusion when implementing custom cache handlers.
Expected behavior: The section introduction states "For durable storage like Redis or a database, you'll need to serialize the cache entries" but doesn't explicitly explain that externalStorage is a placeholder needing implementation. By contrast, the "Basic in-memory cache handler" example shows a complete working implementation using Map, and the self-hosting guide uses explicit comments like "// This could be stored anywhere, like durable storage" for similar placeholders.
Fix applied: Added a clarifying comment at the top of the ExternalCacheHandler class explaining that externalStorage is a placeholder that should be replaced with an actual storage implementation (e.g., Redis client, database connection, Memcached client).
No description provided.