# General Translation Knowledge Base: next-intl vs gt-next: which should you use for Next.js?
URL: https://generaltranslation.com/en-US/kb/next-intl-vs-gt-next.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: next-intl renders translations you supply in a message catalog for each language. gt-next renders translations too, and General Translation also generates them from copy written inline in your JSX. Both are MIT-licensed and support the App Router and Server Components. If your next-intl catalogs already work, you can keep them and use General Translation to translate them without migrating.
Category: Workflow Tools
Authors: Jackie Chen
Published: 2026-10-16

next-intl and gt-next both localize Next.js App Router apps, including Server Components. The difference is where translations come from: next-intl displays messages your team or a translation service writes into a JSON catalog for each language, while gt-next keeps source copy inline in your JSX and General Translation generates every translation as a build step.

That leaves three options. Keep next-intl and your current translation process. Keep next-intl and let General Translation translate its catalogs, with no change to your components. Or adopt gt-next for inline copy and generated translations.

## How do next-intl and gt-next compare?

| Question | next-intl | gt-next (General Translation) |
| --- | --- | --- |
| Does it translate your content? | No. It renders messages you supply, from your team or a service such as Crowdin | Yes. [`gt translate`](/docs/cli/reference/commands/translate) generates translations with context from your code, or your team can write them |
| Where does source copy live? | Keyed messages in a JSON catalog; inline extraction with `useExtracted` is experimental | Inline JSX inside [`<T>`](/docs/react/reference/components/t) and strings through [`useGT`](/docs/react/reference/hooks/use-gt); keyed dictionaries are also supported |
| Server Components? | Yes, with separate APIs for synchronous and asynchronous components | Yes: [`<T>`](/docs/react/reference/components/t), [`useGT`](/docs/react/reference/hooks/use-gt), and [`getGT`](/docs/react/nextjs/reference/functions/get-gt) |
| Client Components? | Under `NextIntlClientProvider` | Under [`GTProvider`](/docs/react/reference/components/gt-provider) |
| Locale routing | Middleware with locale-prefixed routes | [`createNextMiddleware`](/docs/react/nextjs/app-router-middleware) with an `app/[locale]` segment |
| Plurals | ICU MessageFormat in each catalog | [`<Plural>`](/docs/react/reference/components/plural) branches, translated with the rest of the block |
| Translation delivery | Catalog files bundled with the app | Bundled files, or General Translation's CDN for updates without a redeploy |
| License | MIT | MIT |

Sources: [next-intl App Router setup](https://next-intl.dev/docs/getting-started/app-router), [next-intl server and client usage](https://next-intl.dev/docs/environments/server-client-components), [gt-next quickstart](/docs/react/nextjs-quickstart).

## What does the same heading look like in each library?

In next-intl's catalog workflow, the source message lives in a JSON file:

```json
{
  "Projects": {
    "heading": "Find your next project"
  }
}
```

The component selects the message by namespace and key:

```tsx
import { useTranslations } from 'next-intl';

export default function ProjectHeading() {
  const t = useTranslations('Projects');
  return <h1>{t('heading')}</h1>;
}
```

With gt-next, the same sentence stays inside the component:

```tsx
import { T } from 'gt-next';

export default function ProjectHeading() {
  return (
    <T>
      <h1>Find your next project</h1>
    </T>
  );
}
```

Both snippets assume each library's provider and configuration are already in place. See the [next-intl setup guide](https://next-intl.dev/docs/getting-started/app-router) and the [`<T>` reference](/docs/react/reference/components/t).

A catalog lets reviewers read copy separately from the code. Inline copy lets reviewers see each sentence in the JSX it belongs to, and lets General Translation translate it with that structure as context. For wording that is still ambiguous, gt-next's [`<T>` accepts a `context` prop](/docs/react/reference/components/t#context), and next-intl's [experimental extraction supports message descriptions](https://next-intl.dev/docs/usage/extraction#descriptions).

next-intl's experimental [`useExtracted`](https://next-intl.dev/docs/usage/extraction) API also lets you write messages inline and extract them into catalogs. Extraction changes how copy is written. It doesn't translate the extracted catalogs, which still need translations from your team or a service.

## Can you use General Translation without leaving next-intl?

Yes. The `gt` CLI detects next-intl from your `package.json` and [translates its JSON catalogs](/docs/cli/guides/generating-translations) while preserving next-intl's message syntax. Your components, translation calls, and routing stay the same.

To try it, point `gt.config.json` at your source and target catalogs, import the translations you already have, and translate one new locale. Reviewers can correct the output in the [Dashboard Translation Editor](/docs/platform/dashboard/guides/reviewing-translations). If they edit the downloaded catalogs in your repository instead, run [`gt save-local`](/docs/cli/reference/commands/save-local) before the next translation run so those edits are kept.

If you later move to gt-next, the [migration guide](/docs/react/guides/migrating-i18n-libraries) covers importing reviewed translations, keeping your dictionaries, and running both libraries while you migrate one route at a time.

## How does each library handle Server and Client Components?

Neither library requires turning an App Router page into a Client Component to localize it. The difference is which API you call in each environment.

| Component | next-intl | gt-next |
| --- | --- | --- |
| Synchronous Server Component | [`useTranslations`](https://next-intl.dev/docs/environments/server-client-components#using-internationalization-in-server-components), using the request configuration | [`<T>`](/docs/react/reference/components/t) for JSX; [`useGT`](/docs/react/reference/hooks/use-gt) for strings |
| Asynchronous Server Component | Await [`getTranslations`](https://next-intl.dev/docs/environments/server-client-components#async-components) from `next-intl/server` | Await [`getGT`](/docs/react/nextjs/reference/functions/get-gt) from `gt-next/server`, then call the returned function |
| Client Component | [`useTranslations`](https://next-intl.dev/docs/environments/server-client-components#using-internationalization-in-client-components) under `NextIntlClientProvider` | [`<T>`](/docs/react/reference/components/t) or [`useGT`](/docs/react/reference/hooks/use-gt) under [`GTProvider`](/docs/react/reference/components/gt-provider) |

In both libraries, keep interactive controls in Client Components and translate the surrounding page on the server. next-intl also lets you [pass already-translated labels](https://next-intl.dev/docs/environments/server-client-components#option-1-passing-translated-labels-to-client-components) from a Server Component to a client control, so the client doesn't receive the full catalog.

## How are gt-next translations delivered in production?

gt-next supports two delivery options:

- **Bundle translations with the app** using a [local loader](/docs/react/guides/storing-translations). The production app reads its own translation files and makes no runtime calls to General Translation. Updates ship with the next build.
- **Load translations from General Translation's CDN** using the [remote delivery configuration](/docs/react/nextjs/config). Published edits reach the deployed app without a rebuild, subject to its version and cache settings.

gt-next is [MIT-licensed](https://github.com/generaltranslation/gt) and renders bundled translations without a General Translation account, the same way next-intl renders its catalogs.

## Which teams use gt-next in production?

General Translation is used by developer teams at Cursor, Ramp, Profound, Cognition, Sierra, and ClickHouse. Profound localizes its main product, a Next.js App Router app, with General Translation. See [production deployments](https://generaltranslation.com/enterprise).

## When should you choose next-intl or gt-next?

**Keep next-intl** when its catalog model fits your app and your translation process already works. If repetitive key management is the main complaint, try its experimental extraction before migrating.

**Keep next-intl and add General Translation** when translation production is the bottleneck. The `gt` CLI translates your existing catalogs, so your components, calls, and routing don't change.

**Choose gt-next** when you want copy inline in your JSX and translations generated with each build. Trial it on one route that uses both Server and Client Components, plurals, rich text, and metadata. Keep the route's locale URLs and existing translations until their replacements are ready, and check a production build before migrating more routes.

To start, follow the [Next.js App Router quickstart](/docs/react/nextjs-quickstart). To compare more libraries, see [General Translation vs. i18next, react-intl, and next-intl](/kb/general-translation-vs-i18n-libraries).

## Common questions

### Does next-intl translate my content?

No. next-intl renders and formats the messages in your catalogs. Translations come from your team, translators, or a service such as [Crowdin](https://next-intl.dev/docs/workflows/localization-management). General Translation can also translate next-intl catalogs without a migration.

### Can I use General Translation with next-intl?

Yes. The `gt` CLI translates next-intl JSON catalogs and keeps next-intl's message syntax, so you keep your components and routing. See [Generating translations](/docs/cli/guides/generating-translations).

### Is gt-next free and open source?

Yes. gt-next is MIT-licensed and renders bundled translations without an account. For generating translations with General Translation's hosted service, see [pricing](https://generaltranslation.com/pricing).

### Does gt-next support React Server Components?

Yes. Use [`<T>`](/docs/react/reference/components/t) and [`useGT`](/docs/react/reference/hooks/use-gt) in synchronous Server Components, and [`getGT`](/docs/react/nextjs/reference/functions/get-gt) in asynchronous ones.

### Can I migrate from next-intl to gt-next one route at a time?

Yes. The [migration guide](/docs/react/guides/migrating-i18n-libraries) covers running both libraries side by side, importing your existing translations, and keeping keyed dictionaries where you prefer them.

## Key takeaways

- next-intl and gt-next both support the App Router, Server Components, and locale routing, and both are MIT-licensed.
- next-intl renders the translations you supply. gt-next renders them, and General Translation also generates them from inline JSX with your code as context.
- You don't need to migrate to use General Translation: the `gt` CLI translates existing next-intl catalogs.
- If you do migrate, move one route at a time and keep existing translations loaded until their replacements are ready.

## Related questions

- [General Translation vs. i18next, react-intl, and next-intl: which i18n library should you use?](https://generaltranslation.com/en-US/kb/general-translation-vs-i18n-libraries.mdx): Open-source libraries such as i18next, react-intl, and next-intl don't translate anything. They display translations you supply in a catalog file for each language, written by you, your translators, or a separate service. General Translation's libraries are open source too and do the same job, and General Translation also does the translating, with your code as context.
- [How do I set up SEO for a multilingual Next.js app?](https://generaltranslation.com/en-US/kb/multilingual-nextjs-seo.mdx): Give every language its own URL, set the html lang attribute, point each page's canonical URL at itself, add hreflang alternates for every language, translate titles and descriptions, and list every language version in your sitemap.
- [Can I do i18n without translation files?](https://generaltranslation.com/en-US/kb/i18n-without-translation-files.mdx): Yes. With gt-react or gt-next, content stays inline in your components inside a `<T>` component, and translations are generated at build time as output, so there are no keys or per-locale JSON files to write and keep in sync.
- [How do I handle plurals in React?](https://generaltranslation.com/en-US/kb/how-to-handle-plurals-in-react.mdx): Don't hard-code plural logic with checks like n === 1. A small helper is enough for English-only apps, but multilingual apps need locale-aware plural rules, which an i18n component such as `<Plural>` from gt-react or gt-next handles for every language.

## Previous and next questions

- Previous question: [General Translation vs. i18next, react-intl, and next-intl: which i18n library should you use?](https://generaltranslation.com/en-US/kb/general-translation-vs-i18n-libraries.mdx)
- Next question: [What should I check before launching a multilingual app?](https://generaltranslation.com/en-US/kb/multilingual-app-launch-checklist.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/kb/sitemap.md) for every article.
