nextjs-dynamodb-cache
v0.1.0
Published
Drop-in Next.js 14/15/16 CacheHandler that stores ISR cache and tag revalidation in DynamoDB. Survives deploys on AWS Amplify, Lambda, App Runner, and other ephemeral runtimes.
Downloads
16
Maintainers
Readme
nextjs-dynamodb-cache
Drop-in Next.js CacheHandler that stores ISR cache and tag-based revalidation in DynamoDB.
Built for Next.js deployments on AWS Amplify, Lambda, App Runner, ECS, or anywhere your filesystem is ephemeral — so your ISR cache and revalidateTag() calls actually survive deploys and work across instances.
npm install nextjs-dynamodb-cacheWhy
The default Next.js cache handler writes to disk. On Amplify/Lambda/Fargate that means:
- ISR pages re-render from scratch after every deploy
revalidateTag()only invalidates the instance that received the call- Multiple instances serve inconsistent stale content
This package replaces the filesystem cache with DynamoDB. Cache entries are shared across all instances and survive deploys. Tag revalidation uses a GSI so it's a single query, not a full-table scan.
Quick start
1. Create the DynamoDB table
npx nextjs-dynamodb-cache-create-table --table my-app-cache --region eu-central-1This is idempotent. It creates the table, the tag-index GSI, and enables TTL on expiresAt. PAY_PER_REQUEST billing by default.
Or programmatically:
import { createCacheTable } from "nextjs-dynamodb-cache/create-table";
await createCacheTable({ tableName: "my-app-cache", region: "eu-central-1" });2. Register the handler
// next.config.js
module.exports = {
cacheHandler: require.resolve("./cache-handler.mjs"),
cacheMaxMemorySize: 0, // disable in-memory cache so DDB is authoritative
};// cache-handler.mjs
import { DynamoDBCacheHandler } from "nextjs-dynamodb-cache";
export default DynamoDBCacheHandler.configure({
tableName: "my-app-cache",
region: "eu-central-1",
// optional: defaultTtlSeconds, keyPrefix, log, credentials
});That's it. revalidateTag() and revalidatePath() now work cluster-wide.
IAM
The Lambda/Amplify role needs:
{
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:DeleteItem",
"dynamodb:Query",
"dynamodb:BatchWriteItem"
],
"Resource": [
"arn:aws:dynamodb:eu-central-1:*:table/my-app-cache",
"arn:aws:dynamodb:eu-central-1:*:table/my-app-cache/index/*"
]
}Options
| Option | Default | Description |
| --- | --- | --- |
| tableName | env NEXT_CACHE_DYNAMODB_TABLE or nextjs-cache | DynamoDB table name |
| region | env NEXT_CACHE_AWS_REGION / AWS_REGION / eu-central-1 | AWS region |
| credentials | default chain | Explicit AWS credentials |
| tagIndexName | tag-index | GSI name used for revalidateTag |
| defaultTtlSeconds | 604800 (7 days) | TTL when Next.js omits revalidate |
| keyPrefix | "" | Prefix for keys (multi-app table sharing) |
| log | true | Verbose logs on errors and revalidations |
How it works
- Schema: single table, partition key
key. Each entry hasvalue,expiresAt(TTL), and optionaltags. - Tags: for each tag a sentinel row
__tag__<tag>__<key>is written.revalidateTag(t)queries thetag-indexGSI ontag = t, collects the original cache keys, and batch-deletes them. - TTL: DynamoDB native TTL on
expiresAtcleans up stale entries automatically — no cron required. - Resilience: every operation is wrapped in try/catch; a DynamoDB outage degrades to "cache miss," never a 500.
Status
Battle-tested in production on Next.js 16 + Amplify hosting on the HonestDog marketplace. Compatible with Next.js 14, 15, and 16 cache-handler APIs.
License
MIT
