---
createdAt: 2026-06-05
updatedAt: 2026-06-05
title: "Migrate from next-intl to Intlayer | Internationalization (i18n)"
description: "Learn how to migrate your Next.js app from next-intl to Intlayer — step by step, without breaking your existing code. Use the @intlayer/next-intl compat adapter for a zero-disruption transition."
keywords:
- next-intl
- intlayer
- migration
- internationalization
- i18n
- Next.js
- JavaScript
- React
slugs:
- doc
- migration
- next-intl
history:
- version: 8.13.0
date: 2026-06-05
changes: "Init history"
---
# Migrating from next-intl to Intlayer
## Why migrate from next-intl to Intlayer?
Instead of loading massive JSON files into your pages, load only the necessary content. Intlayer helps **reduce your bundle and page sizes by up to 50%**.
Scoping your application's content **facilitates maintenance** for large-scale applications. You can duplicate or delete a single feature folder without the mental burden of reviewing your entire content codebase. Additionally, Intlayer is **fully typed** to ensure your content's accuracy.
Intlayer is also the solution with the **most active development** in the i18n ecosystem — issues are fixed fast, new framework adapters land regularly, and the core API is continuously refined based on real-world production feedback.
Co-locating content **reduces the context needed** by Large Language Models (LLMs). Intlayer also comes with a suite of tools, such as a **CLI** to test for missing translations, **[LSP](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/lsp.md)**, **[MCP](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/mcp_server.md)**, and **[agent skills](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/agent_skills.md)**, to make the developer experience (DX) even smoother for AI agents.
Use automation to translate in your CI/CD pipeline using the LLM of your choice at the cost of your AI provider. Intlayer also offers a **compiler** to automate content extraction, as well as a [web platform](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_CMS.md) to help **translate in the background**.
Connecting massive JSON files to components can lead to performance and reactivity issues. Intlayer optimizes your content loading at build time.
More than just an i18n solution, Intlayer provides a **self-hosted [visual editor](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_visual_editor.md)** and a **[full CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_CMS.md)** to help you manage your multilingual content in **real-time**, making collaboration with translators, copywriters, and other team members seamless. Content can be stored locally and/or remotely.
---
## Migration strategy
The recommended approach for existing apps is the **compat adapter**: install `@intlayer/next-intl`, which exposes the **exact same API** as `next-intl` but delegates all translation work to Intlayer under the hood.
You keep your existing `useTranslations`, `getTranslations`, `NextIntlClientProvider` and friends — **the only change is the import path**. No refactoring of call signatures, prop shapes, or component structure is required.
Over time you can optionally migrate individual files to Intlayer's richer `.content.ts` format to unlock the visual editor, CMS, and per-component content scoping — but that step is entirely optional and can be done incrementally.
---
## Table of Contents
---
## Quick migration
The following steps are the minimum required to get your existing `next-intl` app running on Intlayer with zero code changes.
Install the Intlayer core packages and the `@intlayer/next-intl` compat adapter:
```bash packageManager="npm"
npm install intlayer next-intlayer @intlayer/next-intl @intlayer/sync-json-plugin
npx intlayer init
```
```bash packageManager="pnpm"
pnpm add intlayer next-intlayer @intlayer/next-intl @intlayer/sync-json-plugin
pnpm intlayer init
```
```bash packageManager="yarn"
yarn add intlayer next-intlayer @intlayer/next-intl @intlayer/sync-json-plugin
yarn intlayer init
```
```bash packageManager="bun"
bun add intlayer next-intlayer @intlayer/next-intl @intlayer/sync-json-plugin
bun x intlayer init
```
> Keep `next-intl` installed — it is still required for **URL routing** (`createNavigation`, `createMiddleware`, `Link`, `redirect`, `usePathname`, `useRouter`). The compat adapter does **not** replace the routing layer.
The `intlayer init` command creates a starter `intlayer.config.ts`. Update it to match your existing locales and point the `syncJSON` plugin at your message files:
```typescript fileName="intlayer.config.ts" codeFormat={["typescript", "esm", "commonjs"]}
import { Locales, type IntlayerConfig } from "intlayer";
import { syncJSON } from "@intlayer/sync-json-plugin";
const config: IntlayerConfig = {
internationalization: {
locales: [
Locales.ENGLISH,
Locales.FRENCH,
Locales.SPANISH,
// Add all your existing locales here
],
defaultLocale: Locales.ENGLISH,
},
plugins: [
syncJSON({
// 'icu' matches next-intl's ICU placeholder syntax: {name}, {count, plural, ...}
format: "icu",
source: ({ locale }) => `./messages/${locale}.json`,
location: "messages",
}),
],
};
export default config;
```
> **`source`** maps a locale to its JSON file path. **`location`** tells the Intlayer watcher which folder to monitor for changes. The `format: 'icu'` option ensures ICU placeholders like `{name}` and `{count, plural, one {# item} other {# items}}` are parsed correctly.
> For a complete list of configuration options, see the [configuration documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/configuration.md).
Wrap your existing Next.js config with `createNextIntlPlugin` from `@intlayer/next-intl/plugin`. This wrapper composes `withIntlayer` **and** registers the `next-intl` → `@intlayer/next-intl` aliases for you:
```typescript fileName="next.config.ts" codeFormat={["typescript", "esm", "commonjs"]}
import type { NextConfig } from "next";
import { createNextIntlPlugin } from "@intlayer/next-intl/plugin";
const withIntlayer = createNextIntlPlugin();
const nextConfig: NextConfig = {
/* your existing config options */
};
export default withIntlayer(nextConfig);
```
> `createNextIntlPlugin()` wraps `withIntlayer`, automatically detects **Webpack** or **Turbopack**, wires up content watching, dictionary compilation, and — critically — **injects module aliases** so that your existing `import … from 'next-intl'` calls are transparently redirected to `@intlayer/next-intl` at build time. The routing entry `next-intl/routing` is left pointing at the real package. No source file changes are needed.
>
> Prefer the plain `withIntlayer` from `next-intlayer/server`? It will compile your dictionaries, but it does **not** add the `next-intl` aliases — you would then have to rename imports to `@intlayer/next-intl` manually (see Step 4).
> **You no longer need `getRequestConfig` or `loadMessages`.** With `next-intl`, you had to write a `src/i18n.ts` file that loaded JSON message bundles on every request via `getRequestConfig`. Intlayer compiles all dictionaries at **build time**, so there is no runtime loading step. You can delete that file entirely (or keep only the routing parts if you still use `createNavigation`).
That's it for the quick migration. Your app now runs on Intlayer while keeping every `next-intl` import and API intact.
> **Typed translation keys — automatic.** Once Intlayer compiles your dictionaries, `useTranslations` and `getTranslations` are typed against your actual content. Keys are autocompleted in your IDE and invalid paths cause TypeScript errors at build time — no extra setup required.
>
> ```tsx
> // Client component — 'about' is a registered dictionary key
> const t = useTranslations("about");
> t("counter.label"); // ✓ autocompleted
> t("does.not.exist"); // ✗ TypeScript error
>
> // Server component
> const t = await getTranslations("about");
> t("counter.label"); // ✓ typed
> ```
---
## Complete migration
The steps below are optional and can be done incrementally. They unlock the full Intlayer feature set: visual editor, CMS, typed content files, AI-powered translation, and more.
The `createNextIntlPlugin()` wrapper already handles `next-intl` → `@intlayer/next-intl` aliasing at the bundler level. If you prefer to make the dependency explicit in your source files (and use the plain `withIntlayer` plugin instead), you can rename imports manually:
| Before | After |
| ---------------------------------------------------- | -------------------------------------------------------------- |
| `import { useTranslations } from 'next-intl'` | `import { useTranslations } from '@intlayer/next-intl'` |
| `import { useLocale } from 'next-intl'` | `import { useLocale } from '@intlayer/next-intl'` |
| `import { NextIntlClientProvider } from 'next-intl'` | `import { NextIntlClientProvider } from '@intlayer/next-intl'` |
| `import { getTranslations } from 'next-intl/server'` | `import { getTranslations } from '@intlayer/next-intl/server'` |
| `import { getLocale } from 'next-intl/server'` | `import { getLocale } from '@intlayer/next-intl/server'` |
| `import { setLocale } from 'next-intl/server'` | `import { setLocale } from '@intlayer/next-intl/server'` |
| `import { getMessages } from 'next-intl/server'` | `import { getMessages } from '@intlayer/next-intl/server'` |
> Always keep routing imports from the real `next-intl` — the compat adapter does **not** replace the URL routing layer:
>
> ```ts
> // ✅ Always keep these from the real 'next-intl'
> import { createNavigation } from "next-intl/routing";
> import { createMiddleware } from "next-intl/server";
> import { defineRouting } from "next-intl/routing";
> ```
>
> Alternatively, you can use `defineRouting` from `@intlayer/next-intl/routing` which merges locale config from your `intlayer.config.ts` automatically.
Once Intlayer is wired up, you can use its CLI to fill missing translations automatically using the LLM of your choice:
```bash packageManager="npm"
# Test for missing translations (add to CI)
npx intlayer test
# Fill missing translations with AI
npx intlayer fill
```
```bash packageManager="pnpm"
pnpm intlayer test
pnpm intlayer fill
```
```bash packageManager="yarn"
yarn intlayer test
yarn intlayer fill
```
```bash packageManager="bun"
bun x intlayer test
bun x intlayer fill
```
Add an `OPENAI_API_KEY` (or your preferred provider key) to your `.env` file, then extend your `intlayer.config.ts`:
```typescript fileName="intlayer.config.ts" codeFormat={["typescript", "esm", "commonjs"]}
import { Locales, type IntlayerConfig } from "intlayer";
import { syncJSON } from "@intlayer/sync-json-plugin";
const config: IntlayerConfig = {
internationalization: {
locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
defaultLocale: Locales.ENGLISH,
},
plugins: [
syncJSON({
format: "icu",
source: ({ locale }) => `./messages/${locale}.json`,
location: "messages",
}),
],
ai: {
apiKey: process.env.OPENAI_API_KEY,
// provider: "openai", // default
// model: "gpt-4o-mini", // default
},
};
export default config;
```
> See [Intlayer CLI documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/cli/index.md) for all available options.
---
## What you can delete after migration
Once `@intlayer/next-intl` is in place, the following `next-intl` boilerplate can be removed:
| File / pattern | Why it's no longer needed |
| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `src/i18n.ts` → `getRequestConfig` export | Intlayer compiles dictionaries at build time; there is no per-request message loading. Keep the file only if it also exports `createNavigation` routing helpers. |
| `loadMessages()` / `getMessages()` call in layout | The `NextIntlClientProvider` from `@intlayer/next-intl` reads from compiled output; no `messages` prop is required. |
| `locales/{locale}/*.json` imports in layout | JSON bundles are only needed if you still use the `syncJSON` plugin. Once you migrate to `.content.ts` files you can delete the JSON folder. |
When you are ready to go further, Intlayer **automatically discovers all `.content.ts` and `.content.json` files anywhere in your codebase** (by default, anywhere inside `./src`). You can place an `about.content.ts` file right next to your `about/page.tsx` and Intlayer will pick it up at build time with no additional configuration — no imports, no registration, no centralized index file needed. This makes co-locating translations with pages and components completely frictionless.
---
## Configure TypeScript
Intlayer uses module augmentation to provide full TypeScript intellisense for your translation keys. Make sure your `tsconfig.json` includes the auto-generated types:
```json5 fileName="tsconfig.json"
{
// ... Your existing TypeScript configurations
"include": [
// ... Your existing TypeScript configurations
".intlayer/**/*.ts", // Include the auto-generated types
],
}
```
---
## Git Configuration
Add Intlayer's generated directory to your `.gitignore`:
```plaintext fileName=".gitignore"
# Ignore the files generated by Intlayer
.intlayer
```
---
## Go Further
- **Visual Editor** — Manage translations visually in your browser: [Intlayer Visual Editor](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_visual_editor.md)
- **CMS** — Externalize and manage content remotely: [Intlayer CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_CMS.md)
- **VS Code Extension** — Get autocompletion and real-time translation error detection: [Intlayer VS Code Extension](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/vs_code_extension.md)
- **CLI Reference** — Full list of CLI commands: [Intlayer CLI](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/cli/index.md)
- **Intlayer with Next.js** — Full setup guide for Next.js: [intlayer_with_nextjs_16.md](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_with_nextjs_16.md)