Promote Deployment
Two-Stage Model
feature branch → staging (preview) → main (production)
- staging: Integration branch. Vercel deploys a preview against Neon
stagingdatabase. - main: Production. Vercel deploys to production against Neon
maindatabase.
Usage
Promote to staging (from a feature branch):
./scripts/promote.sh staging
Promote to production (from staging):
./scripts/promote.sh production
The script runs quality gates automatically, checks for uncommitted changes, and creates a PR via gh.
Skill Web
This skill is the release coordinator. Use it first for promotion work, then pull in the domain skill that matches the layer that is failing:
vercel-deployment- Vercel deployment state
- branch-specific deploy failures
- redeploy behavior
- alias cutover issues
github-actions- CI workflow failures
- promotion workflow debugging
- release job behavior
better-auth-best-practices- auth/session failures seen during deploy smoke
organization-best-practices- org-scoping, org bootstrap, or membership issues seen during deploy smoke
Do not jump into those skills first if the problem might simply be release ordering or environment drift. Start here, isolate the failing layer, then branch out.
Prefer Vercel CLI First
For release work in this repo, prefer the Vercel CLI over manual dashboard clicking when the CLI can answer the question.
Most useful commands here:
- Inspect recent deployments:
vercel list --meta githubCommitRef=<branch>vercel list --meta githubCommitSha=<sha>
- Wait for a deployment and inspect logs:
vercel inspect <deployment-url-or-id> --waitvercel inspect <deployment-url-or-id> --logs --wait
- Rebuild an existing deployment:
vercel redeploy <deployment-url-or-id>vercel redeploy <deployment-url-or-id> --target=previewvercel redeploy <deployment-url-or-id> --target=production
- Pull env or run commands with env:
vercel env pull .env.preview-branch --environment preview --git-branch <branch>vercel env run -- <command>
- Pull local project settings for local replication:
vercel pullvercel pull --environment=production
- Production deployment control:
vercel promote <deployment-url-or-id>vercel rollback <deployment-url-or-id>
Use the dashboard when it adds context, not as the default control surface.
Happy Path
Prefer this exact order:
- Run repo gates.
- Push the branch and let Vercel build the preview deployment if branch validation is the goal.
- Verify the exact git ref being promoted.
- Check Vercel deployment state for that exact ref and wait for the preview deployment to exist before continuing with branch-specific env or DB checks.
- Use
vercel env pullonly after the preview deployment exists if you need to discover branch DB wiring:vercel env pull .env.preview-branch --environment preview --git-branch <branch>
- If direct DB access is needed after that, use
neonctl. - Verify Neon branch mapping with
neonctl. - Verify Vercel env parity:
bun run deploy:check-env-parity -- --environment staging --neon-project-id <id>bun run deploy:check-env-parity -- --environment production --neon-project-id <id>
- Rebuild local release artifacts used by smoke:
cd cli && make build
- Provision a real smoke identity:
bun run smoke:provision -- --environment stagingbun run smoke:provision -- --environment production
- Run deployed smoke against the actual hosted URL.
- Only then treat the release as valid.
If any step fails, stop and fix that layer before continuing.
Manual Promotion Checklist
If the script doesn't fit the situation, follow this sequence exactly:
- Generate migrations:
bunx drizzle-kit generate(if schema changed) - Validate migrations:
bun run db:check - Run all gates:
./scripts/gates.sh - Open PR to
staging - Verify
stagingenv parity against Neonstaging - Validate preview deployment against Neon
staging - Open promotion PR from
staging→main - Verify production env parity against Neon
main - Migrations apply automatically during Vercel build via
DATABASE_URL_UNPOOLED - If migration fails, STOP. Do not retry. Fix the schema/migration drift first.
Database Safety
- Migrations run during Vercel's build step using
DATABASE_URL_UNPOOLED(direct connection). - For hosted preview,
staging, and production validation, prefer remote deploys over localdb:pushor direct DDL. - Do not apply migrations manually to shared or preview branches. Let the Vercel build step apply them during remote deploy.
- Do not treat branch env or branch DB state as stable until the preview deployment for that branch actually exists.
- Never assume the deployed app is pointed at the correct Neon branch because a previous release worked.
- If you need direct DB access for a specific preview branch, first discover the wiring via:
vercel env pull .env.preview-branch --environment preview --git-branch <branch>
- Then use
neonctlfor the actual DB access path. - Verify shared-environment routing with:
neonctl branches list --project-id <id>neonctl connection-string staging --project-id <id>neonctl connection-string main --project-id <id>
- Verify Vercel env routing with:
bun run deploy:check-env-parity -- --environment staging --neon-project-id <id>bun run deploy:check-env-parity -- --environment production --neon-project-id <id>
- See the
db-healthskill for full database safety rules.
Environment Mapping
| Git Branch | Vercel Environment | Neon Branch |
|---|---|---|
staging | Preview | staging |
main | Production | main |
| feature branches | Preview (PR) | preview/* (auto-forked) |
Guardrails
- Never push directly to
main. Always go through staging first. - Never skip quality gates to speed up deployment.
- Never skip env-parity checks for shared-environment promotion.
- Never use
drizzle-kit pushorbun run db:pushas a shortcut for hosted preview,staging, ormain. - Treat migration failures as hard blockers — no retry without a fix.
- Treat deploy smoke failures as hard blockers.
- Treat stale local release artifacts as hard blockers for smoke.
- Never run
drizzle-kit pushagainst any shared branch.
Common Pitfalls
- PR preview success does not prove
stagingormaindeploy success. - Vercel author/collaboration failures can be branch-specific.
- Production can be healthy but still point at Neon
staging. - Branch-specific database access should come from
vercel env pull, not guessed endpoints or copied local env files. vercel env pullcan race a brand-new branch push; wait for the preview deployment first.- Direct DB access should go through
neonctl, not copied connection strings. - Live preview URL validation is stronger than local DB poking when the goal is release confidence.
- A stale local
cli/bin/seedcan make deploy smoke fail even when the deployed API is correct. - The release is not complete until the public alias serves the intended deployment id.
If You're Lost
- Vercel deployments & environments
- Neon + Vercel integration
- Drizzle ORM migrations
- See docs/release-flow.md for the full delivery checklist
- See docs/factory-readiness-gaps.md for the remaining factory risks