Back to Guides

Updating large-scale site navigation with minimal revalidation

When working with a large number of pages that share a common multi-level navigation, making a navigation update requires revalidating all pages. Learn how to avoid this by using smart revalidation.
Last updated September 22, 2025
Functions
Frameworks
Edge Network & Caching

When building large-scale websites with thousands or millions of pages using Incremental Static Regeneration (ISR), updating navigation data can cause revalidating every page that includes the navigation component. Since each page regeneration consumes server resources, this widespread revalidation will result in large resource usage in terms of function duration, bandwidth, and hits on the backend.

With Vercel, you can render navigation using build-time data for fast loads, then update it using a shared endpoint to keep all pages current without individual revalidation.

In this guide, you'll learn:

  • How to apply smart revalidation to update navigation without triggering full ISR revalidation for every page, thereby reducing function duration, bandwidth, and backend load.
  • How to fetch navigation data on the client once per session and reuse it across pages for a consistent, fresh experience.
  • How lightweight server-side caching ensures fast responses without overwhelming infrastructure.

Your navigation data stays fresh whilst maintaining good UX using the following process:

  1. The initial render at build time uses server data for instant paint and no layout shift.
  2. The application fetches a shared navigation endpoint once and reuses the data across pages in the same session
  3. Server-side caching refreshes the endpoint periodically to keep responses current without forcing ISR revalidation of every page
  4. Manual triggers such as a CMS webhook or an client-side button, can revalidate the navigation instantly
  5. SWR handles recovery, automatically fetching fresh navigation data when a user reconnects to the internet

This ensures users always see up-to-date navigation while browsing the site, whether through client-side transitions or full page reloads.

Let's review how to implement this by exploring an existing demo repository.

Start by cloning and running the MegaNav Demo repository to see the implementation in action:

terminal
git clone https://github.com/vercel-solutions/meganav-demo.git
cd meganav-demo
pnpm install
pnpm run dev
  1. Open http://localhost:3000 to see the demo running.
  2. Click on Products in the top navigation
  3. Notice how the navigation shows timestamps that update in real-time without affecting page performance

SWR provides automatic polling to keep navigation data fresh on the client side. The following component is imported in the app/layout.tsx file and used in all pages:

components/MegaNav.tsx
const { data: nav } = useSWR<NavigationData>('/api/navigation', fetcher, {
fallbackData,
revalidateOnFocus: false,
revalidateOnMount: true,
revalidateOnReconnect: true,
refreshInterval: 10000, // 10 seconds for demonstration purposes only
});
// Ensure we always have data to render
const navigationData = nav || fallbackData;
Setting refreshInterval to 10 seconds is for demonstration purposes only. In a production environment, you will not need refreshInterval as revalidateOnMount and revalidateOnReconnect are sufficient.

Test SWR behavior:

  1. Open the browser's Network tab
  2. Watch for requests to /api/navigation every 10 seconds
  3. Notice how the navigation timestamps updates automatically

The navigation API uses server-side caching with a 5-minute revalidation period. This ensures fresh data without overwhelming your server.

app/api/navigation/route.ts
import { getNavigationData } from '@/lib/mock-nav';
import { NextResponse } from 'next/server';
export const revalidate = 360; // every 5 minutes for demonstration purposes
export async function GET() {
// needs to be wrapped in the async function in order bundler not to pack it as static
const data = await getNavigationData();
return NextResponse.json(data);
}
In a production environment, you can set the navigation route revalidate time to 1 day and update it with on-demand ISR.

You can trigger immediate navigation updates using ISR on-demand revalidation.

app/api/revalidate/route.ts
import { revalidatePath } from 'next/cache';
import { NextResponse } from 'next/server';
export async function GET() {
try {
revalidatePath('/api/navigation');
return NextResponse.json({ revalidated: true, now: Date.now() });
} catch (err) {
console.log(err);
return NextResponse.json(
{ message: 'Error revalidating' },
{ status: 500 },
);
}}

Test manual revalidation:

  1. Open http://localhost:3000
  2. Click on Products in the top navigation and notice the timestamp for each item
  3. Click the Simulate Headless CMS Change button
  4. Watch the navigation timestamps update immediately
  5. Note that the page content timestamp does not change

You can implement this system directly with a headless CMS. Instead of using a button, you will trigger revalidation with specific CMS events such as content publishing. You can do this with many CMSs using a webhook.

  • Navigation API: Use on-demand ISR with 1 day time-based revalidation. If you use time-based revalidation only, set it to 5-15 minutes for fresh data.
  • ISR Pages: 1-24 hours revalidation for stable content

Couldn't find the guide you need?