typescriptintermediate

Next.js ISR & On-Demand Revalidation

Configure Incremental Static Regeneration with time-based and on-demand revalidation strategies.

typescript
// app/posts/[id]/page.tsx
// Time-based revalidation (ISR)
export const revalidate = 3600; // revalidate every hour

interface Props { params: Promise<{ id: string }> }

export default async function PostPage({ params }: Props) {
  const { id } = await params;
  const post = await fetch(
    `https://api.example.com/posts/${id}`,
    { next: { revalidate: 3600 } }
  ).then(r => r.json());

  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </article>
  );
}

// app/api/revalidate/route.ts
// On-demand revalidation via webhook
import { revalidatePath, revalidateTag } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(req: NextRequest) {
  const secret = req.headers.get('x-revalidate-secret');
  if (secret !== process.env.REVALIDATE_SECRET) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  const { path, tag } = await req.json();
  if (tag) revalidateTag(tag);
  else if (path) revalidatePath(path);

  return NextResponse.json({ revalidated: true, now: Date.now() });
}

// Tag-based fetching
const data = await fetch('https://api.example.com/posts', {
  next: { tags: ['posts'] },
});

Use Cases

  • Caching CMS content with periodic refresh
  • Webhook-triggered cache invalidation

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.