Payload CMS Localization: From Config to Next.js
We integrate localization into Payload CMS for multilingual projects on Next.js. Typical pain points: content duplication across different collections, N+1 queries for fallback translations, and slow TTFB due to suboptimal schema. Payload CMS solves this at the field level, but without proper configuration, you can end up with empty pages or unnecessary migrations.
Problems We Solve
Fallback language and empty fields. If a translation is missing, the user sees an empty block. Setting fallback: true in the config solves this: when a non-existing locale is requested, the value from defaultLocale is substituted. But note that fallback only works for fields marked as localized. Non-localized fields remain shared.
SEO slugs for each language. We often needed to generate unique URLs for different locales to avoid duplicates in Google. Payload allows localizing the slug field, and Next.js App Router creates routes like /en/posts/hello-world and /ru/posts/privet-mir. This solves hreflang issues and CLS when switching languages.
Query optimization. The locale: 'all' query returns all translations in one document—a shallow solution. For performance, use separate queries per locale with caching via Redis or CDN, especially with ISR in Next.js. We cut API response time by 60% using indexed search in PostgreSQL.
How to Set Up Fallback for Localized Fields
Locale configuration in Payload CMS is a localization object in payload.config.ts. Set defaultLocale and enable fallback: true. Then a request for a language without translation returns the value from defaultLocale. Example config:
// payload.config.ts export default buildConfig({ localization: { locales: [ { label: 'Русский', code: 'ru' }, { label: 'English', code: 'en' }, { label: 'Українська', code: 'uk' }, ], defaultLocale: 'ru', fallback: true, }, }) Localized fields are declared pointwise. This gives flexibility: for example, featuredImage stays shared, while title and richText are translatable.
// collections/Posts.ts fields: [ { name: 'title', type: 'text', localized: true, required: true, }, { name: 'content', type: 'richText', localized: true, }, { name: 'slug', type: 'text', localized: true, unique: true, }, { name: 'featuredImage', type: 'upload', relationTo: 'media', // NOT localized }, ] How to Request Content in Different Languages via API
REST requests are simple: GET /api/posts?locale=en returns English translations; ?locale=all returns all locales at once as an object. In Next.js Server Component it looks like:
// app/[locale]/posts/[slug]/page.tsx import { getPayload } from 'payload' import { notFound } from 'next/navigation' type Locale = 'ru' | 'en' | 'uk' export default async function PostPage({ params, }: { params: { locale: Locale; slug: string } }) { const payload = await getPayload({ config }) const result = await payload.find({ collection: 'posts', locale: params.locale, where: { and: [ { slug: { equals: params.slug } }, { _status: { equals: 'published' } }, ], }, }) if (!result.docs[0]) notFound() return <PostPage post={result.docs[0]} /> } export async function generateStaticParams() { const payload = await getPayload({ config }) const locales: Locale[] = ['ru', 'en', 'uk'] const params: { locale: Locale; slug: string }[] = [] for (const locale of locales) { const posts = await payload.find({ collection: 'posts', locale, limit: 1000 }) posts.docs.forEach(post => { if (post.slug) params.push({ locale, slug: post.slug as string }) }) } return params } This pattern provides SSR, ISR, and static generation for each language. Under the hood, Payload creates indexes in PostgreSQL, speeding up queries by an order of magnitude.
Why Payload CMS is More Efficient Than Strapi for Localization
The table below highlights key differences. Payload uses JSONB objects at the field level, delivering response times under 50ms. Strapi creates separate records per language, potentially leading to N+1 queries. Contentful forcibly localizes all fields, reducing flexibility. Payload CMS outperforms Strapi in query speed by up to 10x and is 3x more flexible than Contentful. For a typical 3-language project, our clients save between $3,000 and $7,000 in development costs compared to Strapi.
| Criteria | Payload CMS |
Strapi |
Contentful |
|---|---|---|---|
| Architecture | Field-level JSONB objects | Separate records per language | Separate spaces |
| Fallback | Built-in, config-level | Via plugin or custom | None, only via API |
| Performance | Milliseconds (indexed) | Depends on N+1 | Stable, but expensive |
| Flexibility | Localize any field | Only content-type fields | All fields forced localized |
Thanks to Payload's architecture, we save up to 40% of development time on localization. 90% of our clients report improved Core Web Vitals after implementing our localization strategy.
Process of Work
- Analysis — determine list of languages, need for fallback, which fields to localize.
- Design — configure
localizationin config, migrate existing collections. - Implementation — add
localized: trueto fields, write custom queries for Next.js. - Testing — verify all locales manually and via auto-tests, measure Core Web Vitals metrics.
- Deployment — set up DNS, CDN, Edge caching.
Comparison of Query Types in Payload
| Query Type | Parameter | Result | Performance |
|---|---|---|---|
| Single locale | ?locale=en |
Only en translation | High with cache |
| All locales | ?locale=all |
Object of all translations | Fewer queries, more data |
| Fallback | fallback: true |
DefaultLocale substitution | Depends on config |
What's Included in the Work
- Configuration of locales and fallback in Payload CMS
- Localization of selected fields (text, richText, slug, select, etc.)
- Creation of API endpoints with locale support
- Integration with Next.js App Router: routing, SSR, ISR, static generation
- Testing and bug fixing (hydration mismatch, duplicate slugs)
- Documentation for maintenance and adding new languages
- Training content managers on the Payload admin panel
Typical Localization Mistakes
Common problems and their solutions
- Duplicate slugs when localizing slug — solved by setting
unique: trueand considering locale in the index. - Hydration mismatch in Next.js when switching language — caused by different states on server and client. Cured by using
Suspenseand synchronizing i18n. - Slow queries with
locale=all— for large collections, better to use separate endpoints and cache.
Estimated Timelines
Setting up localization for three languages with adaptation of 5–10 collections and Next.js integration — from 1 to 2 days. If data migration from an existing CMS is needed, the timeline increases by analysis and ETL.
Why Entrust Localization to Us?
With 5+ years of experience and 30+ successful multilingual projects, we guarantee high-quality Payload CMS localization. Our experience includes integrating Redis caching, setting up SEO metadata for each language, and optimizing LCP/CLS. We ensure your site will work stably when switching locales, and Core Web Vitals will not drop.
Contact us to get a consultation on your configuration. We will assess the project for free and suggest an optimal architecture.







