--- name: payload-nextjs-turbopack-fix description: Fix Payload CMS white screen / module load errors when using Next.js 16 with Turbopack tags: [payload, nextjs, turbopack, troubleshooting, white-screen] category: software-development --- # Payload CMS + Next.js 16 Turbopack White Screen Fix ## Symptom Payload CMS admin shows white screen or "initializing" forever. Console/network tab shows: ``` Error: Failed to load external module @payloadcms/db-mongodb-XXXXXXXXXXXX ResolveMessage: Cannot find module '@payloadcms/db-mongodb-XXXXXXXXXXXX' ``` Or server returns HTTP 500 on `/admin/create-first-user` or `/admin`. ## Root Cause **Next.js 16 defaults to Turbopack in dev mode.** Payload CMS 3.x (specifically `@payloadcms/db-mongodb`) is NOT compatible with Turbopack's module resolution — it uses Webpack-specific module IDs that Turbopack can't resolve. ## Fix Steps ### Step 1: Verify MongoDB is running ```bash ss -tlnp | grep -E '27019|27017' pgrep -a mongo ``` MongoDB must be running on the expected port. Check `.env` for `MONGODB_URL`. ### Step 2: Remove Next.js 16-only experimental options from next.config.ts When downgrading from Next 16 → 15, remove any `experimental.turbo` config that was added for Next 16. In Next.js 15 this option doesn't exist and generates a warning: ```ts // WRONG in Next.js 15 — 'turbo' is not a known ExperimentalConfig key experimental: { turbo: undefined, }, // CORRECT — remove experimental.turbo entirely for Next.js 15 ``` ### Step 3: Downgrade Next.js to 15.x (15.5.x) ```bash cd /path/to/moreminimore-next bun add next@15.5.15 react@19.0.0 react-dom@19.0.0 ``` Next.js 15 uses Webpack by default in dev mode, which is fully compatible with Payload CMS. **Why not just disable Turbopack?** - Next.js 16 has NO `--no-turbo` flag (error: unknown option) - `NEXT_TURBOPACK=0` env var does NOT disable Turbopack in Next 16 (still starts with Turbopack) - `experimental.turbo: undefined` in next.config.ts does NOT disable it in Next 16 - Downgrade to Next.js 15.x is the only viable option ### Step 3: Verify version ```bash cat node_modules/next/package.json | grep '"version"' ``` Should show `15.5.x` (not `16.x`). ### Step 4: Clear cache and restart ```bash pkill -9 -f next 2>/dev/null rm -rf .next bun run dev ``` ### Step 5: Verify admin loads Navigate to `http://localhost:3000/admin` — should show Payload login screen. ## Compatibility Matrix | Next.js | Bundler | Payload CMS | Status | |---------|---------|-------------|--------| | 16.x | Turbopack (default) | 3.x | BROKEN | | 16.x | Webpack (flag) | 3.x | No flag available | | 15.5.x | Webpack (default) | 3.x | WORKS | | 14.x | Webpack | 3.x | WORKS | ## Additional Dev Server Issues (Lessons Learned) ### Server crashes after "Ready in Xms" Even with Next.js 15.5.15, the dev server may crash silently right after "Ready" message. Two known causes: **1. `output: 'standalone'` in next.config.ts** This causes Next.js to crash immediately after starting in dev mode. Remove it: ```ts // WRONG — causes crash after "Ready" in dev mode const nextConfig: NextConfig = { output: 'standalone', // REMOVE THIS ... } // CORRECT — no output option in dev const nextConfig: NextConfig = { // (no output key) ... } ``` **2. `NEXT_TURBOPACK=0` in dev script** This env var can cause issues even on Next.js 15. Remove it: ```json // WRONG "dev": "cross-env NODE_OPTIONS=--no-deprecation NEXT_TURBOPACK=0 next dev" // CORRECT "dev": "cross-env NODE_OPTIONS=--no-deprecation next dev" ``` Restart with clean `.next` cache after making changes: ```bash pkill -9 -f next; sleep 1 rm -rf .next bun run dev ``` ### Server starts but port 3000 shows nothing / 404 If `ss -tlnp | grep 3000` shows the port is listening but the site returns 404: 1. Check if there's a compiled `.next` cache from a previous version — always `rm -rf .next` before restarting 2. Verify MongoDB is running: `pgrep -a mongo` 3. Check server logs: `cat /tmp/moredev.log` ## Blog Posts Migration (Astro MD → Payload CMS) Script location: `src/scripts/migrate-posts.ts` Key approach: - Use **absolute paths** for `configPath` and `blogDir` (avoid relative path resolution issues with ESM) - Use **dynamic imports** for Payload config to avoid bundling issues - Store content as plain text (strip markdown syntax with regex replacements) - Check for existing posts by slug before creating (idempotent) ```bash cd /home/kunthawat/moreminimore-next npx tsx src/scripts/migrate-posts.ts ``` ## What to check if still broken 1. **sharp module**: If you see `Failed to load external module sharp-XXX`, check `node_modules/sharp` exists: ```bash ls node_modules/sharp ``` If missing: `bun add sharp` 2. **MongoDB connection**: Ensure `MONGODB_URL` in `.env` matches running mongod port 3. **Port conflict**: If port 3000 is in use: ```bash pkill -9 -f next; pkill -9 -f bun ss -tlnp | grep 3000 ``` 4. **Dev server process shows "Killed" but server is still running**: The `bun run dev` foreground process may get killed by the shell even when the Next.js server starts successfully. Always check port 3000 directly: ```bash ss -tlnp | grep 3000 pgrep -a next-server ``` If port 3000 is listening, the server IS running — ignore the "Killed" message. 5. **TypeScript lint errors from node_modules**: The `next lint` output shows many TS errors from `node_modules/` (e.g., `@types/react`, `next/dist/...`). These are non-blocking noise — they don't prevent the dev server from running or the admin from loading. Ignore them. ## Key Takeaway Next.js 16 + Turbopack is incompatible with Payload CMS 3.x database adapters. Always downgrade to Next.js 15.5.x when using Payload with MongoDB adapter.