2 KiB
| title | source | updated | tags | ||||
|---|---|---|---|---|---|---|---|
| Payload CMS 3.x — (payload)/layout.tsx Must Use RootLayout | daily/2026-05-10.md | 2026-05-10 |
|
Payload CMS 3.x — (payload)/layout.tsx Must Use RootLayout
Problem
In a Payload CMS 3.x + Next.js project, leaving (payload)/layout.tsx empty (or as a pass-through layout) causes the Payload admin panel to crash with a cryptic 500 error:
TypeError: Cannot destructure property 'config' of undefined
The error traces into Payload internals and gives no indication that the layout file is the cause.
Fix
(payload)/layout.tsx must import and render RootLayout from @payloadcms/next/layouts:
// app/(payload)/layout.tsx
import React from 'react'
import { RootLayout } from '@payloadcms/next/layouts'
import { importMap } from './admin/importMap'
import config from '@payload-config'
type Args = {
children: React.ReactNode
}
const Layout = ({ children }: Args) => (
<RootLayout config={config} importMap={importMap}>
{children}
</RootLayout>
)
export default Layout
handleServerFunctions wrapper (for server actions) must be inside a 'use server' block:
// app/(payload)/actions.ts
'use server'
import { handleServerFunctions } from '@payloadcms/next/utilities'
export { handleServerFunctions }
Related Gotchas
Turbopack incompatibility
Payload CMS 3.x is incompatible with Turbopack (Next.js 15 default dev server). The dev script must use --webpack:
"dev": "next dev --webpack"
Without this, hot-reload breaks and some Payload UI features fail silently.
next lint removed in Next.js 16
next lint was removed in Next.js 16. Use ESLint directly:
eslint src/
The lint script in package.json must be updated accordingly.
Why It Happens
Payload CMS injects its context (config, importMap) into the Next.js layout tree. Without RootLayout, the context provider is never mounted, so every Payload component that tries to read the context gets undefined.