---
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.
