1.8 KiB
| title | source | updated | tags | |||||
|---|---|---|---|---|---|---|---|---|
| Payload CMS + Node 26 — Seed Script ESM Workaround | daily/2026-05-10.md | 2026-05-10 |
|
Payload CMS + Node 26 — Seed Script ESM Workaround
Problem
Running a Payload CMS seed script directly via npx tsx seed.ts on Node 26 fails with:
ERR_REQUIRE_ESM: require() of ES Module ... not supported
or module resolution errors because Node 26's stricter ESM/CJS interop breaks the way Payload loads its config and collections outside a Next.js process.
Fix: Seed via API Route
Instead of a standalone script, expose seed logic as a Next.js API route and call it from a running dev server:
// app/api/seed/route.ts
import { getPayload } from 'payload'
import config from '@payload-config'
import { NextResponse } from 'next/server'
export async function GET() {
const payload = await getPayload({ config })
// Check if already seeded
const existing = await payload.find({ collection: 'users', limit: 1 })
if (existing.totalDocs > 0) {
return NextResponse.json({ message: 'Already seeded' })
}
await payload.create({
collection: 'users',
data: {
email: 'admin@example.com',
password: 'changeme',
role: 'admin',
},
})
return NextResponse.json({ message: 'Seeded successfully' })
}
Then seed by hitting http://localhost:3000/api/seed while the dev server is running.
Why This Works
The API route runs inside the already-running Next.js process which has already resolved all ESM/CJS module boundaries correctly. getPayload({ config }) reuses the singleton Payload instance without a standalone boot sequence.
Future
Remove this workaround once Payload officially supports Node 26 module resolution. The standalone seed approach (payload/dist/bin/seed) is cleaner but requires ESM-stable Node.