Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
468 changes: 258 additions & 210 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion examples/redis-minimal/.env
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
NEXT_PRIVATE_DEBUG_CACHE="1"
REDIS_URL="redis://localhost:6379"
REDIS_SINGLE_CONNECTION=true
REDIS_SINGLE_CONNECTION=false
238 changes: 227 additions & 11 deletions examples/redis-minimal/README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,248 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
# Next.js Cache Handler Examples

This example application demonstrates various Next.js caching functionalities using the Redis cache handler. It provides a comprehensive UI to explore and test different caching strategies.

## Getting Started

First, run the development server:
First, install dependencies:

```bash
npm i
npm run dev
```

Or run build and run production server:
### Important: Development vs Production Mode

**Next.js does not use the cache handler in development mode.** This is a Next.js limitation - caching is intentionally disabled in dev mode for faster hot reloading and to ensure developers always see fresh data.

To test caching functionality, you must use **production mode**:

```bash
npm i
npm run build
npm run start
```

For development (without caching):

```bash
npm run dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

Modify `.env` file if you need to.
## Configuration

Modify the `.env` file if you need to configure Redis connection settings. The default Redis URL is used if not specified.

## Examples

- http://localhost:3000
- http://localhost:3000/fetch-example
- http://localhost:3000/static-params-test/cache
The application includes several examples demonstrating different Next.js caching features:

### 1. Home Page (`/`)

Overview page listing all available examples with descriptions and features.

### 2. Default Cache (`/examples/default-cache`)

Demonstrates the default fetch caching behavior with `force-cache`.

**Features:**

- Default caching behavior (indefinite cache duration)
- Perfect for static or rarely-changing data
- Shows how Next.js caches by default

**Try it:**

- Visit `/examples/default-cache` to see cached data
- The timestamp will remain the same on subsequent requests
- Data is cached until manually cleared or build is redeployed

### 3. No Store (`/examples/no-store`)

Shows fetch with `no-store` option, which always fetches fresh data.

**Features:**

- Never caches responses
- Always fetches fresh data from API
- Perfect for real-time or user-specific data
- Timestamp changes on every request

**Try it:**

- Visit `/examples/no-store` to see fresh data on every load
- Refresh the page multiple times - timestamp changes each time
- Compare with other caching strategies

### 4. Time-based Revalidation (`/examples/time-based-revalidation`)

Shows fetch with time-based revalidation (standalone, without tags).

**Features:**

- Automatic revalidation after specified time (30 seconds)
- Balances freshness with performance
- Standalone example of `next.revalidate`

**Try it:**

- Visit `/examples/time-based-revalidation` to see cached data
- Refresh within 30 seconds - timestamp stays the same
- Wait 30+ seconds and refresh - timestamp updates

### 5. Fetch with Tags (`/examples/fetch-tags`)

Demonstrates fetch caching with tags and time-based revalidation.

**Features:**

- Time-based revalidation (24 hours)
- Cache tags for selective invalidation
- Clear cache button to test tag revalidation
- Shows character data from Futurama API
- Displays cache information and rendered timestamp

**Try it:**

- Visit `/examples/fetch-tags` to see cached data
- Click "Clear Cache" to invalidate the cache
- Reload the page to see fresh data

### 6. unstable_cache (`/examples/unstable-cache`)

Demonstrates persistent caching with `unstable_cache` for function results.

**Features:**

- Cache any function, not just fetch requests
- Tags and revalidation support
- Side-by-side comparison with fetch caching
- Perfect for database queries and computations
- Shows when to use unstable_cache vs fetch

**Try it:**

- Visit `/examples/unstable-cache` to see both caching methods
- Compare the timestamps and behavior
- Click "Clear Tag Cache" to invalidate both caches
- Understand when to use unstable_cache vs fetch

### 7. revalidateTag() with cacheLife (`/examples/revalidate-tag-cachelife`)

Demonstrates the updated `revalidateTag()` API in Next.js 16 with cacheLife profiles.

**Features:**

- Breaking change from Next.js 15 (cacheLife now required)
- Different cacheLife profiles: 'max', 'hours', 'days'
- Stale-while-revalidate behavior
- Examples for each profile type
- Code examples showing migration from Next.js 15

**Try it:**

- Visit `/examples/revalidate-tag-cachelife` to see all three profiles
- Click "Revalidate" buttons to test each profile
- Compare the behavior of different cacheLife profiles
- See code examples for Next.js 15 vs Next.js 16

### 8. ISR with Static Params (`/examples/isr/blog/[id]`)

Incremental Static Regeneration with `generateStaticParams`.

**Features:**

- Static generation at build time
- On-demand regeneration
- Time-based revalidation (1 hour)
- Multiple blog post routes

**Try it:**

- Visit `/examples/isr/blog/1` for the first post
- Try different IDs like `/examples/isr/blog/2`, `/examples/isr/blog/3`
- Check the rendered timestamp to see caching in action

### 9. Static Params Test (`/examples/static-params/[testName]`)

Tests static params generation with dynamic routes.

**Features:**

- Static params generation
- Dynamic params support
- Short revalidation period (5 seconds) for testing
- Shows generation type (static vs dynamic)

**Try it:**

- Visit `/examples/static-params/cache` (pre-generated)
- Try `/examples/static-params/test1` or `/examples/static-params/test2` (on-demand)

## API Routes

### Cache Revalidation (`/api/revalidate`)

Unified endpoint for revalidating cache by tag or path.

**Usage:**

**Tag-based revalidation (GET):**

- `GET /api/revalidate?tag=futurama` - Revalidates cache for the "futurama" tag with 'max' profile
- `GET /api/revalidate?tag=futurama&cacheLife=hours` - Revalidates with 'hours' profile
- `GET /api/revalidate?tag=futurama&cacheLife=days` - Revalidates with 'days' profile

**Tag-based revalidation (POST):**

- `POST /api/revalidate` with body `{ "tag": "futurama" }` - Revalidates cache for a tag (defaults to 'max')
- `POST /api/revalidate` with body `{ "tag": "futurama", "cacheLife": "hours" }` - Revalidates with specific profile

**Path-based revalidation (POST):**

- `POST /api/revalidate` with body `{ "path": "/examples/default-cache" }` - Revalidates cache for a specific path

**Examples:**

```bash
# Revalidate by tag (GET) - defaults to 'max' profile
curl http://localhost:3000/api/revalidate?tag=futurama

# Revalidate by tag with specific profile (GET)
curl http://localhost:3000/api/revalidate?tag=futurama&cacheLife=hours

# Revalidate by tag (POST) - defaults to 'max' profile
curl -X POST http://localhost:3000/api/revalidate \
-H "Content-Type: application/json" \
-d '{"tag": "futurama"}'

# Revalidate by tag with specific profile (POST)
curl -X POST http://localhost:3000/api/revalidate \
-H "Content-Type: application/json" \
-d '{"tag": "futurama", "cacheLife": "days"}'

# Revalidate by path (POST)
curl -X POST http://localhost:3000/api/revalidate \
-H "Content-Type: application/json" \
-d '{"path": "/examples/default-cache"}'
```

## Cache Handler

This example uses a custom Redis cache handler configured in `cache-handler.mjs`. The handler supports:

- Redis string-based caching
- Local LRU fallback
- Composite caching strategy
- Tag-based cache invalidation

**Note:** The cache handler only works in production mode. In development mode, Next.js bypasses the cache handler entirely. You'll see a warning message in the console: `"Next.js does not use the cache in development mode. Use production mode to enable caching."`

## Clear fetch example cache
## Technologies

- http://localhost:3000/api/cache
- Next.js 16
- React 19
- TypeScript
- Tailwind CSS
- Redis
- @fortedigital/nextjs-cache-handler
24 changes: 13 additions & 11 deletions examples/redis-minimal/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { dirname } from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const compat = new FlatCompat({
baseDirectory: __dirname,
});
import nextCoreWebVitals from "eslint-config-next/core-web-vitals";
import nextTypescript from "eslint-config-next/typescript";

const eslintConfig = [
...compat.extends("next/core-web-vitals", "next/typescript"),
...nextCoreWebVitals,
...nextTypescript,
{
ignores: [
"node_modules/**",
".next/**",
"out/**",
"build/**",
"next-env.d.ts",
],
},
];

export default eslintConfig;
3 changes: 0 additions & 3 deletions examples/redis-minimal/next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ import type { NextConfig } from "next";
const nextConfig: NextConfig = {
cacheHandler: require.resolve("./cache-handler.mjs"),
cacheMaxMemorySize: 0, // disable default in-memory caching
experimental: {
//ppr: "incremental",
},
};

export default nextConfig;
21 changes: 12 additions & 9 deletions examples/redis-minimal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,27 @@
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "next lint"
"lint": "eslint ."
},
"dependencies": {
"@fortedigital/nextjs-cache-handler": "workspace:*",
"next": "^15.5.6",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"redis": "^5.9.0"
"next": "16.0.3",
"react": "19.2.0",
"react-dom": "19.2.0",
"redis": "^5.10.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@tailwindcss/postcss": "^4",
"@types/node": "^24",
"@types/react": "^19",
"@types/react-dom": "^19",
"@types/react": "19.2.6",
"@types/react-dom": "19.2.3",
"eslint": "^9",
"eslint-config-next": "15.5.6",
"eslint-config-next": "16.0.3",
"tailwindcss": "^4",
"typescript": "^5"
},
"overrides": {
"@types/react": "19.2.6",
"@types/react-dom": "19.2.3"
}
}
6 changes: 0 additions & 6 deletions examples/redis-minimal/src/app/api/cache/route.ts

This file was deleted.

Loading