# General Translation Knowledge Base: next-intl alternatives: gt-next vs. next-intl
URL: https://generaltranslation.com/en-GB/kb/next-intl-vs-gt-next.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: next-intl renders translations you supply in a message catalogue 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 catalogues already work, you can keep them and use General Translation to translate them without migrating.
Category: Workflow Tools
Last updated: 2026-10-16
Authors: Jackie Chen
Published: 2026-10-16

next-intl and gt-next both localise Next.js App Router apps, including Server Components. The difference is where translations come from: next-intl displays messages that your team or a translation service writes into a JSON catalogue for each language, whereas 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 catalogues, with no changes to your components. Or adopt gt-next for inline copy and generated translations.

## Video

The video is narrated in English, with English captions.

[next-intl alternatives: gt-next vs. next-intl](https://caxecubb9c64cezv.public.blob.vercel-storage.com/films/kb-next-intl-vs-gt-next.mp4) (43 secs)

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; if your next-intl catalogs already work, keep them and let the `gt` CLI translate them without migrating. Or move to `gt-next`, write copy inside a `<T>` component, and run `npx gt translate` before your build.

## 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 catalogue; 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 catalogue                                                       | [`<Plural>`](/docs/react/reference/components/plural) branches, translated with the rest of the block                                                                  |
| Translation delivery            | Catalogue files bundled with the app                                                      | Bundled files, or General Translation&#39;s CDN for updates without a redeploy                                                                                         |
| Licence                         | MIT                                                                                       | MIT                                                                                                                                                                    |

Sources: [next-intl App Router set-up](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&#39;s catalogue 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&#39;s provider and configuration are already in place. See the [next-intl set-up guide](https://next-intl.dev/docs/getting-started/app-router) and the [`<T>` reference](/docs/react/reference/components/t).

A catalogue 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&#39;s [`<T>` accepts a `context` prop](/docs/react/reference/components/t#context), and next-intl&#39;s [experimental extraction supports message descriptions](https://next-intl.dev/docs/usage/extraction#descriptions).

next-intl&#39;s experimental [`useExtracted`](https://next-intl.dev/docs/usage/extraction) API also lets you write messages inline and extract them into catalogues. Extraction changes how copy is written. It doesn&#39;t translate the extracted catalogues, which still need translating by 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 catalogues](/docs/cli/guides/generating-translations) while preserving next-intl&#39;s message syntax. Your components, translation calls and routing stay the same.

To try it, point `gt.config.json` at your source and target catalogues, 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 catalogues in your repository instead, run [`gt save-local`](/docs/cli/reference/commands/save-local) before the next translation run so that 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 side by side while you migrate one route at a time.

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

Neither library requires you to turn an App Router page into a Client Component in order to localise it. The difference lies in 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&#39;t receive the full catalogue.

## 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&#39;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, in the same way that next-intl renders its catalogues.

## Which teams use gt-next in production?

General Translation is used by developer teams at Cursor, Ramp, Profound, Cognition, Sierra and ClickHouse. Profound localises 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 catalogue model suits 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 catalogues, so your components, calls and routing don&#39;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 Server and Client Components, plurals, rich text and metadata. Keep the route&#39;s locale URLs and existing translations until their replacements are ready, and check a production build before migrating more routes.

To get started, 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 catalogues. 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 catalogues without a migration.

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

Yes. The `gt` CLI translates next-intl JSON catalogues and preserves next-intl&#39;s message syntax, so you can keep your existing 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&#39;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.

## Other next-intl alternatives

For Next.js apps, teams also compare these libraries:

* **i18next:** renders keyed catalogues with plural selection, and with react-i18next and next-i18next is a common choice for React and Next.js apps. (See [General Translation vs. i18next](/kb/general-translation-vs-i18next).)
* **react-intl:** formats ICU messages and has a guide for the Next.js App Router. (See [General Translation vs. react-intl](/kb/general-translation-vs-react-intl).)
* **Paraglide JS:** compiles catalogues into typed, tree-shakable message functions, with a Next.js integration for webpack builds. (See [General Translation vs. Paraglide JS](/kb/general-translation-vs-paraglide).)

## 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, using your code as context.
* You don&#39;t need to migrate to use General Translation: the `gt` CLI translates existing next-intl catalogues.
* 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-GB/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 catalogue 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, but General Translation also does the translating, using your code as context.
- [How do I set up SEO for a multilingual Next.js app?](https://generaltranslation.com/en-GB/kb/multilingual-nextjs-seo.mdx): Give each language its own prefixed URL, such as /en/about and /es/about, then publish html lang, a self-referencing canonical, hreflang alternates with x-default, a translated title and description, and a sitemap entry for each published language. Mark unpublished versions noindex. General Translation's gt-next routes each language to its own URL and translates titles with getGT.
- [Can I do i18n without translation files?](https://generaltranslation.com/en-GB/kb/i18n-without-translation-files.mdx): Yes. General Translation's gt-react and gt-next libraries do React and Next.js i18n with no translation keys and no JSON file per language to maintain. Copy stays inline in JSX inside the `<T>` component, and the gt translate command generates each language's translations in your build, with context from your code. Locadex can keep them up to date through pull requests.
- [How do I handle plurals in React?](https://generaltranslation.com/en-GB/kb/how-to-handle-plurals-in-react.mdx): Handle plurals in React by giving each language one sentence per plural form and picking it with that language's plural rules, since English has 2 forms, Russian has 4 and Arabic has 6. General Translation's `<Plural>` component in gt-react and gt-next takes your source forms, and General Translation generates the forms each target language needs.

## Previous and next questions

- Previous question: [Lokalise alternatives: General Translation vs. Lokalise](https://generaltranslation.com/en-GB/kb/general-translation-vs-lokalise.mdx)
- Next question: [Phrase alternatives: General Translation vs. Phrase](https://generaltranslation.com/en-GB/kb/general-translation-vs-phrase.mdx)

## Sitemap

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