Keep schema changes safe and repeatable across local development, preview, and production without destructive resets.
- All shared schema changes must be committed as Payload migrations in
src/migrations/**. migrate:freshis allowed only for local disposable/test databases.- Preview and production move forward only with
pnpm payload migrate. - Long-running seed operations should run through the Developer Dashboard job queue, not request-bound runtime execution.
-
DB Quality workflow (GitHub Actions) DB Quality starts a local Postgres service, applies migrations, and runs
pnpm payload migrate:statuswhen DB-relevant files changed. -
Pull Request build job (GitHub Actions) The build job starts a local Postgres service and prepares a disposable build database before
pnpm build. Migration status and schema/migration enforcement live in DB Quality. -
Preview deployment (Vercel) Vercel executes the deployment environment preflight and then
pnpm run civiavercel.json. The preflight validatesCLINIC_DASHBOARD_URLbeforepnpm run ciruns migrations and the Next.js build. -
Production deployment (Vercel) Same as preview: the deployment environment preflight runs before migrations and the build.
- Change schema-related code (
src/collections/**,src/globals/**, etc.). - Generate migration:
pnpm payload migrate:create <name>. - Apply locally:
pnpm payload migrate. - Verify:
pnpm payload migrate:status. - Commit schema and migration files together.
- Open PR and wait for CI gates.
Use an expand/backfill/switch/contract flow for changes that rename fields, move data, harden constraints, or remove data.
- Expand: add the new field, table, relation, or nullable/defaulted constraint without removing the old shape.
- Backfill: copy or transform existing data with an idempotent migration or operator script. Re-running the backfill must not corrupt data.
- Switch: update application reads and writes to prefer the new shape. Keep compatibility with the old shape until the active deployment no longer depends on it.
- Contract: remove the old field, table, fallback, or data only in a later release after production has run successfully on the new shape.
Rules:
- Treat field renames as
add new field -> backfill -> switch reads/writes -> drop old field. - Introduce required fields as nullable or defaulted first, backfill them, verify null counts, and harden the constraint later.
- Keep destructive SQL (
DROP COLUMN,DROP TABLE,TRUNCATE,DELETE FROM) out of the first release that introduces replacement storage. - Document before/after counts for backfills and destructive cleanup.
- Confirm backup / point-in-time recovery before any contract-stage migration that removes production data.
- Prefer soft-delete or archival states before hard deletion when business data may still be needed.
Production data checks:
- CI must not query production databases.
- Use a backup restore, snapshot, or read replica as the default source for production-shape verification.
- Direct production reads are an exception and require a technically read-only role, bounded
SELECTqueries, and a documented migration decision.
- If schema-related files changed but no migration files were committed, CI runs a Payload alignment check.
- If Payload can generate a migration, CI fails until migration files are committed.
- This catches “forgot migration” issues before preview/production deploys.
- The DB Quality workflow always runs a required gate job, while heavy migration checks run only for DB-relevant changes.
- DB Quality applies migrations to a local CI Postgres instance and runs
pnpm payload migrate:status. - The advisory migration risk scan warns on destructive or compatibility-sensitive SQL patterns; warnings do not block merges until the policy is intentionally tightened.
- Do not fix production schema drift with
migrate:fresh. - Use forward migrations for fixes.
- Ensure database backup / point-in-time recovery is available before production deploys.
- If preview must be reset in an emergency, use the manual Reset Database workflow (Preview only).
Use the Developer Dashboard to start baseline or demo runs.
Flow:
- A platform user clicks Seed Baseline or Seed Demo in the Developer Dashboard.
POST /api/seedqueues a run and stores the run snapshot under a generatedrunId.- The dashboard stores only
runIdlocally and restores the exact run from the server after reload. - Payload jobs process the queued work in the background until the run reaches a terminal state.
Policy guardrails:
- Baseline is allowed in all runtimes.
- Demo is blocked in production.
- Baseline reset is blocked in production.
- Demo reset is blocked in production.
Endpoint note:
POST /api/seedis the dashboard entrypoint and is available to platform users indevelopment,test,preview, andproduction.GET /api/seedrestores the run snapshot from the server;GET /api/seed?runId=...is the exact-run lookup used after reload.
-
Runtime crash on Vercel (
ERR_REQUIRE_ESM)- Error shape:
An error occurred while loading the instrumentation hookrequire() of ES Module /var/task/.next/server/instrumentation.js ... not supported
- Seen on
websitepreview/production deployments built with Next.js16.2.0 (Turbopack).
- Error shape:
-
Invalid Next config warning
experimental.isolatedDevBuildbecame invalid after Next.js16.2.0.
next builduses Turbopack by default in Next.js 16; webpack is opt-in via--webpack.experimental.isolatedDevBuildwas removed (reason from Next.js PR #89167: the behavior is now default, with separate dev/build output locations).- Result: after upgrading to
16.2.0, two things can happen at once:- an expected config warning for the removed flag,
- and a separate runtime regression in the Turbopack instrumentation path.
- The app is ESM (
"type": "module") and usessrc/instrumentation.ts. - In failing Turbopack deployments, Vercel/Next runtime startup attempted to load
.next/server/instrumentation.jsviarequire(). - In an ESM package scope, that load path can fail with
ERR_REQUIRE_ESM, which aborts instrumentation initialization and breaks affected dynamic routes (for example/admin/login). - This error pattern is not unique to this repository; a similar Turbopack + instrumentation
ERR_REQUIRE_ESMincident is documented upstream in Next.js issue #78705.
Important:
- The
isolatedDevBuildwarning is not the runtime crash root cause. - Removing that flag fixes config validation noise only.
- Webpack and Turbopack generate and bootstrap server runtime artifacts differently.
- In our deploys, the Turbopack runtime path hit the instrumentation load failure; webpack builds (
Next.js 16.2.0 (webpack)) did not reproduce that signature. - Therefore
next build --webpackis a compatibility mitigation for this specific runtime path, while staying on Next.js16.2.0.
- The failure is request-time on server routes, not a compile-time hard stop.
- A deployment can look “green” until affected routes are hit, then fail with instrumentation-hook errors.
- This explains why one release can appear okay initially while a subsequent release quickly shows errors once traffic reaches those routes.
- Also,
v0.27.0->v0.27.1changed only dependency overrides/tests (no direct app-runtime logic changes), so timing and route coverage can change what is observed first.
- Force webpack for production builds:
package.json->build:next build --webpack
- Remove unsupported config:
next.config.js-> removeexperimental.isolatedDevBuild
- Stop tracking generated Next typing artifact:
- add
next-env.d.tsto.gitignore - run
next typegenexplicitly inpnpm check
- add
Only revert the webpack fallback when all conditions are met:
- A stable Next.js release demonstrably fixes the instrumentation ESM runtime path on Vercel.
websitepreview and production pass at least 3 consecutive deployments without instrumentation-hook runtime errors.- No regression in Payload admin routes (
/admin/login,/admin, API auth routes) under real preview traffic.
- ADR 023 documents the long-lived production build decision: Production build webpack fallback.
- Next.js CLI docs (
next build: Turbopack default,--webpackoverride): https://nextjs.org/docs/app/api-reference/cli/next - Next.js
v16.2.0release notes (includesIsolatedDevBuild flag removal): https://github.com/vercel/next.js/releases/tag/v16.2.0 - Next.js PR #89167 (why
isolatedDevBuildwas removed): vercel/next.js#89167 - Related upstream issue (
ERR_REQUIRE_ESMin instrumentation with Turbopack): vercel/next.js#78705
-
Application team (
website)- Keep
next build --webpackas the active mitigation until rollback criteria are met. - Keep
experimental.isolatedDevBuildremoved. - Monitor preview and production logs for instrumentation-hook regressions.
- Maintain this runbook and the related tracking issue.
- Keep
-
Next.js / Turbopack maintainers (upstream)
- Own stabilization of Turbopack instrumentation loading in ESM projects.
- Own fixes for
ERR_REQUIRE_ESM-class regressions in generated server runtime paths.
-
Vercel runtime/platform team (upstream)
- Own runtime-loader compatibility in Vercel server functions when Turbopack output is used.
- Co-own fixes when failures are specific to Vercel deploy/runtime behavior.
- Open/maintain a GitHub issue in this repository to track rollback readiness.
- If the same
ERR_REQUIRE_ESMinstrumentation signature reappears on current stable Next.js, open:- a Next.js upstream issue (or update existing upstream thread),
- and a Vercel support ticket with affected deployment IDs and timestamps.
- Re-run rollback validation after each Next.js upgrade affecting Turbopack/runtime behavior.