Skip to content
Merged
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
121 changes: 109 additions & 12 deletions examples/redis-minimal/README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,130 @@
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 build # important to run once to create cacheHandler dist file
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. 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

### 3. 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

### 5. 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

### Clear Cache (`/api/cache`)

Clears cache for a specific tag.

**Usage:**

- `GET /api/cache?tag=futurama` - Clears cache for the "futurama" tag
- Default tag is "futurama" if not specified

**Example:**

```bash
curl http://localhost:3000/api/cache?tag=futurama
```

## 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
18 changes: 15 additions & 3 deletions examples/redis-minimal/src/app/api/cache/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import { revalidateTag } from "next/cache";
import { NextRequest } from "next/server";

export async function GET() {
revalidateTag("futurama", "max");
return new Response("Cache cleared for futurama tag");
export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams;
const tag = searchParams.get("tag") || "futurama";

try {
revalidateTag(tag, "max");
return new Response(`Cache cleared for tag: ${tag}`, {
status: 200,
});
} catch (error) {
return new Response(`Error clearing cache for tag: ${tag}`, {
status: 500,
});
}
}
168 changes: 168 additions & 0 deletions examples/redis-minimal/src/app/examples/fetch-tags/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import { ExampleLayout } from "@/components/ExampleLayout";
import { ClearCacheButton } from "@/components/ClearCacheButton";
import { InfoCard } from "@/components/InfoCard";
import { CodeBlock } from "@/components/CodeBlock";
import { FuturamaCharacter } from "@/types/futurama";

export default async function FetchTagsExample() {
let name: string;
let character: FuturamaCharacter;
const timestamp = new Date().toISOString();

try {
const characterResponse = await fetch(
"https://api.sampleapis.com/futurama/characters/1",
{
next: {
revalidate: 86400,
tags: ["futurama"],
},
}
);
character = await characterResponse.json();
name = character.name.first;
} catch (error) {
console.error("Error fetching character data:", error);
return (
<ExampleLayout
title="Fetch with Tags Example"
description="Demonstrates fetch caching with tags and time-based revalidation"
>
<div className="text-red-600 dark:text-red-400">
An error occurred during fetch. Please check your network connection.
</div>
</ExampleLayout>
);
}

return (
<ExampleLayout
title="Fetch with Tags Example"
description="This example demonstrates fetch caching with tags and time-based revalidation. The data is cached for 24 hours and can be invalidated using the 'futurama' tag."
actions={<ClearCacheButton tag="futurama" />}
>
<div className="space-y-6">
<InfoCard title="How it works">
<ul className="list-disc list-inside space-y-1">
<li>
Data is fetched with a 24-hour revalidation period (
<code className="bg-gray-200 dark:bg-gray-800 px-1 rounded">
revalidate: 86400
</code>
)
</li>
<li>
Cache is tagged with{" "}
<code className="bg-gray-200 dark:bg-gray-800 px-1 rounded">
&quot;futurama&quot;
</code>{" "}
for selective invalidation
</li>
<li>
Click &quot;Clear Cache&quot; to invalidate the cache and see
fresh data on reload
</li>
<li>
The timestamp shows when this page was rendered (cached pages will
show the same timestamp)
</li>
</ul>
</InfoCard>

<div className="space-y-4">
<div>
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2">
Character Data
</h2>
<div className="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 space-y-2">
<div>
<span className="font-medium text-gray-700 dark:text-gray-300">
Name:
</span>{" "}
<span className="text-gray-900 dark:text-gray-100">{name}</span>
</div>
{character.name.middle && (
<div>
<span className="font-medium text-gray-700 dark:text-gray-300">
Middle Name:
</span>{" "}
<span className="text-gray-900 dark:text-gray-100">
{character.name.middle}
</span>
</div>
)}
<div>
<span className="font-medium text-gray-700 dark:text-gray-300">
Last Name:
</span>{" "}
<span className="text-gray-900 dark:text-gray-100">
{character.name.last}
</span>
</div>
{character.occupation && (
<div>
<span className="font-medium text-gray-700 dark:text-gray-300">
Occupation:
</span>{" "}
<span className="text-gray-900 dark:text-gray-100">
{character.occupation}
</span>
</div>
)}
</div>
</div>

<div>
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2">
Cache Information
</h2>
<div className="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<div>
<span className="font-medium text-gray-700 dark:text-gray-300">
Rendered at:
</span>{" "}
<span className="text-gray-900 dark:text-gray-100 font-mono text-sm">
{timestamp}
</span>
</div>
<div className="mt-2">
<span className="font-medium text-gray-700 dark:text-gray-300">
Cache Tag:
</span>{" "}
<code className="bg-gray-200 dark:bg-gray-800 px-2 py-1 rounded text-sm">
futurama
</code>
</div>
<div className="mt-2">
<span className="font-medium text-gray-700 dark:text-gray-300">
Revalidation:
</span>{" "}
<span className="text-gray-900 dark:text-gray-100">
24 hours
</span>
</div>
</div>
</div>
</div>

<div>
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2">
Code Example
</h2>
<CodeBlock>
{`const response = await fetch(
"https://api.sampleapis.com/futurama/characters/1",
{
next: {
revalidate: 86400,
tags: ["futurama"],
},
}
);`}
</CodeBlock>
</div>
</div>
</ExampleLayout>
);
}

Loading