Documentation

Vercel deploy

Git sources, both Vercel projects, ignore wiring and manual production deploys for the monorepo.

Git sources

The repository is mirrored across three sources:

  • GitLab (gitlab.com:isyuricunha/website): the deploy source. Both Vercel projects connect their Git integration to this repository, so pushes to main trigger production builds.
  • GitHub (github.com/isyuricunha/website): mirror and CI surface. The account is rate-limited, so GitHub Actions runs are not relied on.
  • YuGit/Forgejo (ssh.git.yuricunha.com:2222): self-hosted mirror.

Push to all three:

git push gitlab main
git push origin main
git push yugit main

Projects

Two Vercel projects serve this monorepo:

ProjectRoot DirectoryProduction domainServes
website-webapps/webyuricunha.comthe website
website-docsapps/docsdocs.yuricunha.comthe docs app

Both are Node.js 24.x with the Next.js framework preset. apps/docs/vercel.json carries its own install and build commands because the build needs the monorepo root:

{
  "installCommand": "pnpm -C ../.. install --frozen-lockfile",
  "buildCommand": "pnpm -C ../.. --filter @isyuricunha/docs build"
}

Ignore wiring and crons

In a monorepo with Root Directory set, Vercel reads vercel.json from inside the Root Directory and runs the ignore command from there; a repository-root vercel.json is dead config for git-triggered builds.

  • apps/web/vercel.json (used by website-web) declares the ignore command and the cron schedules for /api/cron/alerts and /api/cron/data-retention. Its ignore script (apps/web/scripts/vercel-ignore.js) is a wrapper that executes the repository-root script, which skips changes that only touch apps/docs/, README, license and metadata-only paths.
  • apps/docs/vercel.json (used by website-docs) mirrors the pattern: its ignore script skips changes that only touch apps/web/.

A docs-only change therefore builds website-docs and skips website-web; a web-only change does the opposite. Declaring crons in the app-level vercel.json keeps them attached on every deployment instead of relying on dashboard state.

Automatic deploys

A push to GitLab main triggers production builds in both projects, filtered by the ignore wiring. If a push did not trigger a deploy (integration freshly connected or webhooks missing), run a manual production deploy.

Run manual deploys from the repository root, not from inside the app directory. A CLI deploy from apps/web uploads only that subdirectory and fails with The specified Root Directory "apps/web" does not exist. Please update your Project Settings. because the project's Root Directory setting is applied on top of the uploaded tree.

website-web is the repository-root link by default:

pnpm exec vercel deploy --prod --yes

website-docs needs a temporary link swap because the root link points at website-web:

mv .vercel .vercel-web
pnpm exec vercel link --project website-docs --yes
pnpm exec vercel deploy --prod --yes
rm -rf .vercel
mv .vercel-web .vercel

Avoid leaving vercel link artifacts inside app directories (.vercel/, .env.local): they are local tooling files and can confuse later CLI deploys.

Verify the serving revision

Probes confirm which revision is live:

  • Call an endpoint whose response shape changed in the release and check the new behavior.
  • For docs releases, request a newly added recipe page on docs.yuricunha.com.
  • Inspect response headers; CSP changes appear immediately.

Do not rely on deployment dashboard status alone: a Ready deployment is promoted to production traffic only when it becomes the production alias.

Migrations are not run on deploy

Vercel builds do not run database migrations. After merging schema changes, apply them manually:

pnpm db:check
pnpm db:migrate

Run the preflight checklist in Drizzle first; the migrator stops mid-journal if a migration references objects that already exist or constraints that do not.

Edit on GitHub