--- name: payload-v3-admin-init description: Create the first admin user in Payload CMS v3 via an internal API route. Solves the missing onInit hook problem. category: devops --- # Payload v3 — Create Admin User via API Route ## Problem No admin user exists in Payload CMS. Login page at `/admin` shows email/password form but no user was created on first boot. ## Key Finding: No `onInit` Hook in Payload v3 Payload v3 `buildConfig()` does NOT have an `onInit` hook. The v2 pattern `hooks: { init: [...] }` does not exist. Adding it causes TypeScript errors. ## Solution: Create Admin via API Route **File:** `src/app/api/create-admin/route.ts` ```typescript import { NextResponse } from 'next/server' import { getPayload } from 'payload' import config from '@/payload.config' export async function POST() { try { const p = await getPayload({ config }) const existing = await p.find({ collection: 'users', limit: 1 }) if (existing.totalDocs > 0) { return NextResponse.json({ message: 'Admin already exists', email: existing.docs[0].email }) } const result = await p.create({ collection: 'users', data: { email: 'admin@dealplustech.co.th', password: 'DealPlus2026!', }, }) return NextResponse.json({ success: true, email: result.email }) } catch (err: any) { return NextResponse.json({ error: err.message }, { status: 500 }) } } ``` Then call: ```bash curl -X POST http://localhost:3001/api/create-admin ``` ## Common Errors | Error | Cause | Fix | |-------|-------|-----| | `the payload config is required for getPayload to work` | Used `getPayload({ mongoURL })` instead of `getPayload({ config })` | Pass `config` import | | `GET /api/users` returns 403 | Auth required — cannot list users without being logged in | Use internal API route instead | | `onInit` in `buildConfig()` TypeScript error | Hook doesn't exist in v3 | Remove it, use API route | ## Verification After creating, visit `/admin` and login with the credentials set in the API route.