- Payload CMS locale 'all': Fetch every language in one query
Payload CMS locale 'all': Fetch every language in one query
Payload CMS locale 'all': get every locale for static paths and sitemaps — avoid localized where bugs.

Moving to Next.js and Payload CMS? I offer advisory support on an hourly basis.
Book Hourly Advisorylocale: 'all' — Fetch Every Language in One QueryMost Payload CMS localization tutorials show you how to fetch content in a single locale: pass locale: 'en' to payload.find(), get English back. Pass locale: 'de', get German. Simple enough.
But there's a less documented parameter that changes the query entirely: locale: 'all'. Instead of returning content in one language, it returns every locale's data in a single request — fields come back as objects keyed by locale rather than single translated values.
This matters most in two situations: building static paths for CMS-driven pages at build time, and generating sitemaps that need every language variant of every URL. In both cases, the naive approach is N queries per locale. locale: 'all' collapses that into one.
There's a catch, though. The parameter works differently depending on whether you combine it with a where clause — and getting that wrong leads to a bug that's hard to diagnose. This guide covers both cases with confirmed patterns from the Payload community.
locale: 'all' Actually ReturnsWhen you pass a specific locale to payload.find(), localized fields return as plain values:
// locale: 'en' — field returns a string
{
id: '123',
title: 'Our Services',
slug: 'services',
}
When you pass locale: 'all', localized fields return as objects keyed by locale code. Non-localized fields return as normal values:
// locale: 'all' — localized fields return as keyed objects
{
id: '123', // non-localized — returns as normal value
title: { // localized: true — returns as keyed object
en: 'Our Services',
de: 'Unsere Leistungen',
sl: 'Naše storitve',
},
slug: { // localized: true — returns as keyed object
en: 'services',
de: 'leistungen',
sl: 'storitve',
},
price: 499, // non-localized — returns as normal value
}
This is confirmed in the Payload docs: "The response will be structured so that field values come back as the full objects keyed for each locale instead of the single, translated value."
The same parameter works in the REST API as ?locale=all or ?locale=*:
curl "https://localhost:3000/api/services?locale=all&limit=100"
locale: 'all' works cleanly when you're fetching documents without filtering on a localized field. The most common use case is pulling all documents from a collection to extract slugs for static generation or sitemap building.
// File: src/lib/payload/getAllServices.ts
import { getPayload } from 'payload'
import config from '@payload-config'
export async function getAllServicesAllLocales() {
const payload = await getPayload({ config })
const result = await payload.find({
collection: 'services',
locale: 'all',
draft: false,
limit: 1000,
pagination: false,
})
return result.docs
}
Each document comes back with localized fields as keyed objects. You then loop over your locales to extract the values you need:
// File: src/app/[locale]/services/[slug]/page.tsx
import { routing } from '@/i18n/routing'
import { getAllServicesAllLocales } from '@/lib/payload/getAllServices'
export async function generateStaticParams() {
const services = await getAllServicesAllLocales()
const params: { locale: string; slug: string }[] = []
for (const service of services) {
// slug is a localized field — comes back as { en: '...', de: '...', sl: '...' }
const slugField = service.slug as Record<string, string> | undefined
if (!slugField) continue
for (const locale of routing.locales) {
const slug = slugField[locale]
if (slug) {
params.push({ locale, slug })
}
}
}
return params
}
One query, every locale, every slug. At build time this means Next.js has everything it needs to pre-render /en/services/services, /de/services/leistungen, and /sl/services/storitve without any additional API calls.
Here's where developers get burned. If you try to combine locale: 'all' with a where clause that filters on a localized field — like finding a document by its slug — the results are unreliable.
Issue #11212 in the Payload repository exists specifically because of this. The problem is that locale: 'all' changes the internal structure of fields, and where queries on those fields behave inconsistently when the field is stored as a locale-keyed object rather than a plain value.
Do not do this:
// ⚠️ Unreliable — where on a localized field with locale: 'all'
const result = await payload.find({
collection: 'services',
locale: 'all',
where: {
slug: { equals: 'leistungen' }, // localized field — unreliable with locale: 'all'
},
})
The confirmed working pattern from the Payload community for querying by localized slug is to use a specific locale per query, not locale: 'all'.
When you need to find a document by its slug in a specific locale — which is what every [slug]/page.tsx does at request time — query with the exact locale, not 'all':
// File: src/lib/payload/getServiceBySlug.ts
import { getPayload } from 'payload'
import config from '@payload-config'
import type { Locale } from '@/i18n/routing'
export async function getServiceBySlug(slug: string, locale: Locale) {
const payload = await getPayload({ config })
const result = await payload.find({
collection: 'services',
locale, // specific locale — reliable with where clause
fallbackLocale: 'en',
draft: false,
limit: 1,
where: {
slug: { equals: slug },
},
})
return result.docs[0] ?? null
}
// File: src/app/[locale]/services/[slug]/page.tsx
import { setRequestLocale } from 'next-intl/server'
import { getServiceBySlug } from '@/lib/payload/getServiceBySlug'
import { notFound } from 'next/navigation'
import type { Locale } from '@/i18n/routing'
export default async function ServicePage({
params,
}: {
params: Promise<{ locale: Locale; slug: string }>
}) {
const { locale, slug } = await params
setRequestLocale(locale)
const service = await getServiceBySlug(slug, locale)
if (!service) {
notFound()
}
return (
<article>
<h1>{service.title}</h1>
</article>
)
}
The split is clean: locale: 'all' in generateStaticParams to build the path list at build time, specific locale in the page component to fetch the actual document at render time.
The other place locale: 'all' earns its keep is sitemap generation. A multilingual sitemap needs every URL variant for every document — and doing that with per-locale queries multiplies your API calls by the number of locales you support.
// File: src/app/sitemap.ts
import { getPayload } from 'payload'
import config from '@payload-config'
import { routing } from '@/i18n/routing'
import type { MetadataRoute } from 'next'
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const payload = await getPayload({ config })
const baseUrl = process.env.NEXT_PUBLIC_SERVER_URL!
const services = await payload.find({
collection: 'services',
locale: 'all',
draft: false,
limit: 1000,
pagination: false,
})
const entries: MetadataRoute.Sitemap = []
for (const service of services.docs) {
const slugField = service.slug as Record<string, string> | undefined
if (!slugField) continue
for (const locale of routing.locales) {
const slug = slugField[locale]
if (!slug) continue
entries.push({
url: `${baseUrl}/${locale}/services/${slug}`,
lastModified: service.updatedAt,
alternates: {
languages: Object.fromEntries(
routing.locales
.filter((l) => slugField[l])
.map((l) => [l, `${baseUrl}/${l}/services/${slugField[l]}`])
),
},
})
}
}
return entries
}
One query for all services, all locales, all slug variants. The alternates.languages object gives search engines the hreflang data they need to understand the relationship between language versions.
One active issue worth knowing about before shipping to production: if a localized relationship field has been removed from a document and left null in the database, querying with locale: 'all' throws a 500 error in Payload 3.28.
The error is:
Cannot read properties of null (reading 'relationTo')
This was reported in issue #11864 against both the REST and Local APIs. If your collections have relationship fields marked as localized: true, audit them for null values before relying on locale: 'all' in production. Either ensure the field always has a value, or add error handling around the query until the fix lands.
Use locale: 'all' when:
generateStaticParamsUse a specific locale when:
where on a localized field like slugThe two patterns work together: locale: 'all' at build time to enumerate paths, specific locale at render time to fetch the right content. Keep them in separate functions and the distinction stays clear.
Let me know in the comments if you run into edge cases with this — particularly around relationship fields and locale: 'all', which seems to be where most of the rough edges are. Subscribe for more practical development guides.
Thanks, Matija
Detailed Payload guides with field configuration examples, custom components, and workflow optimization tips to speed up your CMS development process.