From 580a864ea3bc723130f8aeb7743232a1063e3093 Mon Sep 17 00:00:00 2001 From: EagleFox31 <86088743+EagleFox31@users.noreply.github.com> Date: Sun, 11 Oct 2026 23:45:15 +0000 Subject: [PATCH] build: apply Payload migrations automatically on Vercel deploys Add a vercel-build script that runs db:migrate over the direct Neon connection before next build, so each environment migrates its own Neon branch on deploy instead of relying on a manual step. --- README.md | 2 +- docs/deployment.md | 8 ++++++++ package.json | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a21ad79..c12653a 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ pnpm build Set `DATABASE_URL` (pooled), `DATABASE_URL_UNPOOLED` (direct), `PAYLOAD_SECRET`, `CRON_SECRET`, `PREVIEW_SECRET`, `NEXT_PUBLIC_SERVER_URL` and `BLOB_READ_WRITE_TOKEN`. The Blob token is injected automatically when a Vercel Blob store is connected to the project. -The initial migration is committed in `src/migrations`. Apply pending migrations using the direct connection before deploying: +Migrations are committed in `src/migrations`. On Vercel they are applied automatically: the `vercel-build` script runs `pnpm run db:migrate` (direct connection) before `next build`, on the Neon branch of each environment. See `docs/deployment.md`. Outside Vercel, run the same steps: ```bash pnpm db:migrate diff --git a/docs/deployment.md b/docs/deployment.md index ad508fc..0822882 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -14,6 +14,14 @@ Never use the production connection for local development or preview deployments `DATABASE_URL` uses the pooled hostname, while `DATABASE_URL_UNPOOLED` uses the direct hostname. The `db:migrate*` commands set `PAYLOAD_MIGRATING=true` so Payload selects the direct connection. Schema push is disabled; all changes use committed Payload migrations. +## Automatic migrations on deploy + +Vercel runs the `vercel-build` script instead of `build` when it exists: `pnpm run db:migrate && pnpm run build`. Every deployment therefore applies pending Payload migrations to the Neon branch of its own environment (Preview → development branch, Production → production branch) over `DATABASE_URL_UNPOOLED`, before `next build`. Already-applied migrations are skipped, so a deploy without schema changes is a no-op for the database. If a migration fails, the build fails and the previous deployment keeps serving traffic. + +Requirements: `DATABASE_URL_UNPOOLED`, `DATABASE_URL` and `PAYLOAD_SECRET` must be available to the build in each Vercel environment, and the project's *Build Command* setting must be left on its default (an override bypasses `vercel-build`). + +Migrations must stay backward compatible with the deployment still serving traffic (additive changes first, removals in a later release), because the database is migrated before the new code goes live. + ## Initial migration verification — 2026-09-09 Payload generated `20260909_073929` from the editorial collections, followed by two integrity migrations for authorship, research-source uniqueness, and query indexes. Development and production each contain 92 tables and all three `payload_migrations` records. diff --git a/package.json b/package.json index be9398e..c873177 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "db:migrate:status": "cross-env PAYLOAD_MIGRATING=true payload migrate:status", "build": "cross-env NODE_OPTIONS=--no-deprecation next build", "postbuild": "next-sitemap --config next-sitemap.config.cjs", + "vercel-build": "pnpm run db:migrate && pnpm run build", "dev": "cross-env NODE_OPTIONS=--no-deprecation next dev", "dev:prod": "cross-env NODE_OPTIONS=--no-deprecation rm -rf .next && pnpm build && pnpm start", "generate:importmap": "cross-env NODE_OPTIONS=--no-deprecation payload generate:importmap",