ISR stopped working after introducing next-intl

2025-08-03

There was a clear explanation on the official site, but I completely overlooked it—so here's a quick note for future reference.


How to support Static Rendering with next-intl

There are two ways to do this:

  1. Handle all pages via a Layout
  2. Handle each page individually

In most cases, option 1 should suffice.

Using Layout to support all pages

import { setRequestLocale } from 'next-intl/server';
import { hasLocale } from 'next-intl';
import { notFound } from 'next/navigation';
import { routing } from '@/i18n/routing';

export function generateStaticParams() {
  return routing.locales.map((locale) => ({ locale }));
}

export default async function LocaleLayout({ children, params }) {
  const { locale } = params;

  if (!hasLocale(routing.locales, locale)) {
    notFound();
  }

  // Enable static rendering
  setRequestLocale(locale);

  return (
    // ...
  );
}

This is the recommended approach. However, if the associated page has additional dynamic parameters—such as in /[locale]/blog/[slug]—you’ll need to define generateStaticParams accordingly.


Using Page-level configuration

import { use } from 'react';
import { setRequestLocale } from 'next-intl/server';
import { useTranslations } from 'next-intl';
import { routing } from '@/i18n/routing';

export const revalidate = 86400;

export function generateStaticParams() {
  return routing.locales.map((locale) => ({ locale }));
}

export default function IndexPage({params}) {
  const { locale } = use(params);

  // Enable static rendering
  setRequestLocale(locale);

  // Once the request locale is set, you
  // can call hooks from `next-intl`
  const t = useTranslations('IndexPage');

  return (
    // ...
  );
}

This is probably less common, but works fine for isolated cases.


You can also verify that ISR is configured properly in your local environment:

npm run build
npm run start
curl -I http://localhost:3000/hoge

If the Cache-Control header includes s-maxage with the same value as your revalidate setting, you're good to go.

Note: Due to Vercel's infrastructure, s-maxage is not exposed via curl when targeting a deployed URL—so don’t expect to see it in production.


In summary, even after introducing next-intl, as long as static rendering is properly configured via Layout or Page and the revalidation behavior is understood, ISR works just fine—which is reassuring.