---
createdAt: 2025-05-20
updatedAt: 2025-06-29
title: Static vs Dynamic Rendering with i18n in Next.js
description: Learn how to use static vs dynamic rendering with i18n in Next.js.
keywords:
  - static
  - dynamic
  - rendering
  - i18n
  - next.js
  - next-intl
  - intlayer
  - framework
  - middleware
  - configuration
slugs:
  - frequent-questions
  - static-rendering
---

# Static vs Dynamic Rendering with i18n in Next.js

## The issue with **next-intl**

- **What happens?**
  When you use `useTranslations`, `getTranslations`, or any next-intl helper _inside a Server Component_ on an i18n-routed app (`/en/…`, `/fr/…`), Next.js marks the whole route as **dynamic**. ([Next Intl][1])

- **Why?**
  next-intl looks up the current locale from a request-only header (`x-next-intl-locale`) via `headers()`. Because `headers()` is a **dynamic API**, any component that touches it loses static optimisation. ([Next Intl][1], [Next.js][2])

- **Official workaround (boilerplate)**
  1. Export `generateStaticParams` with every supported locale.
  2. Call `setRequestLocale(locale)` in **every** layout/page _before_ you call `useTranslations`. ([Next Intl][1])
     This removes the header dependency, but you now have extra code to maintain and an unstable API in production.

## How **intlayer** sidesteps the problem

**Design choices**

1. **Route-param only** – The locale comes from the `[locale]` URL segment that Next.js already passes to every page.
2. **Compile-time bundles** – Translations are imported as regular ES modules, so they’re tree-shaken and embedded at build-time.
3. **No dynamic APIs** – `useT()` reads from React context, not from `headers()` or `cookies()`.
4. **Zero extra config** – Once your pages live under `app/[locale]/`, Next.js prerenders one HTML file per locale automatically.
