Payload Plugins
Pluginspayload-dev-tools

The /dev pages

Every /dev route and what it shows, plus the GET /api/dev snapshot that describes your whole app in one request.

For AI / LLMs: View Markdown

One catch-all file mounts a set of routes that render your app's real content — seeded docs, icons, fonts, images, videos — inside your own layout. A companion GET /api/dev endpoint returns the same picture as JSON for tooling and AI agents.

The /dev pages

The pages render content only; navigation between them is the toolbar's Pages view, which stays open as you browse. Views light up based on which plugins are installed:

RouteWhat you see
/devEnv + plugin chips, seed card (seed / destructive reseed with errors inline), the environment card (which env file booted, database host, missing variables), doc counts.
/dev/iconsEvery icon set as a button. Click one to activate it and the whole site re-skins. Plus the active set's glyph grid and runtime misses.
/dev/fontsInteractive specimen per family slot. Click through only the weights and styles the typeface actually serves.
/dev/imagesOriginals rendered through /api/img/:id?w=320, exercising the transform + cache end-to-end. Payload folders render as filter chips.
/dev/muxVideos with their persisted ingest status.
/dev/revalidatepayload-revalidate's tag graph, tracked reads, and recent revalidation events (when payload-revalidate is installed).
/dev/tests/<key>One page per test, showing the toolbar-selected version. No added chrome, so you see the component exactly as it would ship. See The test harness.

Your own labs coexist: a static route like app/(frontend)/dev/blocks/page.tsx always beats the catch-all, and the toolbar's links puts it in the Pages view.

The snapshot: GET /api/dev

JSON for everything non-human (?format=json also forces it); browsers are redirected to /dev.

curl -s localhost:3000/api/dev | jq '.seed.seeded, .icons.misses'
{
  "generatedAt": "2025-01-01T12:00:00.000Z",
  "env": {
    "nodeEnv": "development", "nodeVersion": "v22.x", "name": "staging", "file": ".env.staging",
    "database": { "variable": "DATABASE_URI", "host": "localhost", "local": true },
    "vars": [{ "name": "PAYLOAD_SECRET", "owner": "payload", "required": true, "set": true }/* … */],
    "warnings": []
  },
  "adminRoute": "/admin",
  "devRoute": "/dev",
  "regions": [{ "code": "DE", "label": "Germany", "regime": "gdpr", "consent": "opt-in" }/* … */],
  "plugins": { "seed": true, "images": true, "icons": true, "fonts": true, "mux": true, "revalidate": true },
  "seed": { "enabled": true, "seeded": true, "totalDocs": 42, "counts": { "services": 4 }, "definitions": [/* … */] },
  "images": { "sourceSlug": "images", "basePath": "/api/img", "sourceCount": 12, "variantCount": 96 },
  "icons": { "iconCount": 9, "activeSet": "Brand icons", "misses": [{ "name": "sparkles", "count": 7 }] },
  "fonts": { "familyKeys": ["sans", "serif"], "slots": { "sans": "Inter", "serif": null } },
  "mux": { "slug": "mux-video", "credentialed": false, "total": 0, "ready": 0 },
  "revalidate": { "endpointPath": "/api/revalidate-map", "prefix": "", "observing": true, "edges": 12, "reads": 8, "events": 3 },
  "collections": [{ "slug": "services", "count": 4 }/* … */],
  "globals": ["site-settings"]
}

Each plugin panel is null when that plugin isn't installed. One request answers "what is this app, is it seeded, and what's broken."

env reports presence, never values — set booleans and the database host with its credentials stripped. See Environments.

On this page