This is a monorepo for @neshca/cache-handler
package that provides a cache handler for Next.js Incremental Static Regeneration (ISR). It is meant to be used with the experimental.incrementalCacheHandlerPath
configuration option of Next.js. More information about this option can be found in the Next.js documentation.
Native Next.js ISR cache can't be shared between multiple instances. @neshca/cache-handler
on the other hand can be used with a local or remote cache store. So you can share the cache between multiple instances of your application. In the example below, you can see how to use Redis as a cache store.
Sharing the cache between multiple instances is useful if you are using a load balancer or Kubernetes for deployment.
To install the @neshca/cache-handler
package, run the following command:
npm install -D @neshca/cache-handler
Create a file called cache-handler.js
next to you next.config.js
with the following contents:
const { IncrementalCache } = require('@neshca/cache-handler');
const { reviveFromBase64Representation, replaceJsonWithBase64 } = require('@neshca/json-replacer-reviver');
const { createClient } = require('redis');
const client = createClient({
url: process.env.REDIS_URL,
name: 'app:cache-testing',
});
client.connect().then();
client.on('error', (err) => {
console.log('Redis Client Error', err);
});
IncrementalCache.prefix = 'app:cache-testing:';
IncrementalCache.cache = {
async get(...args) {
const result = await client.get(...args);
if (!result) {
return null;
}
try {
return JSON.parse(result, reviveFromBase64Representation);
} catch (error) {
return null;
}
},
async set(key, value, ttl) {
await client.set(key, JSON.stringify(value, replaceJsonWithBase64), { EX: ttl });
},
async getTagsManifest(prefix) {
const tagsManifest = await client.hGetAll(`${prefix}tagsManifest`);
if (!tagsManifest) {
return { version: 1, items: {} };
}
const items = {};
for (const [tag, revalidatedAt] of Object.entries(tagsManifest)) {
items[tag] = { revalidatedAt: parseInt(revalidatedAt ?? '0', 10) };
}
return { version: 1, items };
},
async revalidateTag(prefix, tag, revalidatedAt) {
const options = {
[tag]: revalidatedAt,
};
await client.hSet(`${prefix}tagsManifest`, options);
},
};
module.exports = IncrementalCache;
Then, use the following configuration in your next.config.js
file:
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
incrementalCacheHandlerPath: require.resolve('./cache-handler'), // path to the cache handler file you created
isrFlushToDisk: false, // disable writing cache to disk
},
};
module.exports = nextConfig;
Use the REDIS_URL
environment variable to set the URL of your Redis instance.
REDIS_URL=redis://localhost:6379/
To get started with development, install the project dependencies using npm ci
. Then, run npm run dev
to start the development server and watch for changes to the handler
and server
modules:
npm ci
npm run build
npm run dev
In a separate terminal, run the cache-testing
app using npm run build:app
and npm run start:app
. Note that you need to rebuild the cache-testing
app every time the handler
module is rebuilt:
npm run build:app
npm run start:app
Remember that you need to rebuild cache-testing
every time handler
rebuild is happening.
To use Redis as the cache store, you can use Docker to start a Redis instance with the following command:
docker run -d --name redis-stack -p 6379:6379 -p 8001:8001 redis/redis-stack:latest
Then, create a .env.local
file inside the apps/cache-testing
directory and add the REDIS_URL
environment variable:
REDIS_URL=redis://localhost:6379
Finally, use the handler-redis
module in next.config.js
to configure the cache handler. The isrFlushToDisk
field is required and should be set to false
:
const nextConfig = {
experimental: {
incrementalCacheHandlerPath: require.resolve('./cache-handler-redis'),
isrFlushToDisk: false,
},
};
Then, run the following commands to start the development server and the cache-testing
app:
npm run dev:redis
npm run build:app
npm run start:app
Before committing changes, run the linting and formatting jobs using npm run lint
and npm run format
.
npm run lint
npm run format
When you run npm run dev
the server
package is in watch mode. So it drops in-memory cache every time you make a change in sources.
If you are using VS Code and see a Parsing error: Cannot find module 'next/babel'
error in .js
files, create a .vscode/settings.json
file in the root of the project and add the following configuration:
{
"eslint.workingDirectories": [{ "pattern": "apps/*/" }, { "pattern": "packages/*/" }, { "pattern": "utils/*/" }]
}