YeetCode
Guides

Production Deployments — Vercel

Deploy and manage the marketing site on Vercel using release-please and GitHub Actions.

The marketing site (apps/marketing) is deployed to Vercel via GitHub Actions, triggered by release-please version tags. This approach gives you full control over when production deployments happen — not on every commit, but on deliberate releases.

How It Works

The flow mirrors the backend deployment, but targets Vercel instead of Convex:

commit to main → release-please PR → merge → tag created → Vercel deploy

Production Deploy Workflow

The workflow at .github/workflows/deploy-marketing.yaml triggers on marketing@v* tags:

on:
  push:
    tags:
      - marketing@v*

env:
  VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
  VERCEL_PROJECT_ID: ${{ secrets.VERCEL_MARKETING_PROJECT_ID }}

jobs:
  deploy-frontend:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v1
      - run: npm install -g vercel@canary
      - run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
      - run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
      - run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}

The key steps are:

  1. vercel pull — downloads the project settings and environment variables from Vercel
  2. vercel build --prod — builds the Next.js app locally in the CI runner
  3. vercel deploy --prebuilt --prod — uploads the pre-built output to Vercel for production

Setup Steps

1. Disable Vercel's Git Integration

Since we're deploying via GitHub Actions, you need to disable Vercel's built-in automatic deployments to avoid double-deploying:

  1. Go to your Vercel project → Settings → Git
  2. Under Deploy Hooks, leave empty (we don't use these)
  3. Under Ignored Build Step, set to: exit 0 — this tells Vercel to skip its own builds entirely

Alternatively, you can disconnect the GitHub repo from the Vercel project entirely and rely solely on CLI deployments from GitHub Actions.

2. Get Vercel IDs and Token

You need three values from Vercel:

Vercel Token:

  1. Go to vercel.com/account/tokens
  2. Create a new token with a descriptive name (e.g. "YeetCode GitHub Actions")
  3. Scope it to your team if using Vercel Teams

Org ID and Project ID:

  1. Go to your Vercel project → Settings → General
  2. Scroll to Project ID — copy it
  3. Go to your Vercel team → Settings → General → copy the Team ID (this is your Org ID)

Or run locally:

npm install -g vercel@canary
vercel link
cat .vercel/project.json
# Shows: { "orgId": "...", "projectId": "..." }

3. Add GitHub Secrets

In your GitHub repo, go to Settings → Secrets and variables → Actions and add:

SecretDescription
VERCEL_TOKENYour Vercel API token
VERCEL_ORG_IDYour Vercel team/org ID
VERCEL_MARKETING_PROJECT_IDProject ID for the production marketing site

4. Set Environment Variables in Vercel

Your Next.js app needs environment variables at build time. Set these in the Vercel dashboard for each project (production and test):

  1. Go to your Vercel project → Settings → Environment Variables
  2. Add all required variables (check apps/marketing/.env.example or .env.local for the list)
  3. Common ones include:
    • NEXT_PUBLIC_CONVEX_URL — your Convex deployment URL
    • NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY — Clerk publishable key
    • CLERK_SECRET_KEY — Clerk secret key (server-only)

These are pulled by vercel pull during the CI build.

All Required GitHub Secrets

Here's the complete list of secrets needed for the full deployment pipeline (backend + marketing):

SecretUsed byDescription
MY_RELEASE_PLEASE_TOKENrelease-pleaseGitHub PAT for creating release PRs and tags
CONVEX_DEPLOY_KEY_PRODUCTIONdeploy-backendConvex production deploy key
VERCEL_TOKENdeploy-marketingVercel API token
VERCEL_ORG_IDdeploy-marketingVercel team/org ID
VERCEL_MARKETING_PROJECT_IDdeploy-marketingProduction Vercel project ID

Files Involved

FilePurpose
release-please-config.jsonRegisters the marketing app for versioning
release-please-manifest.jsonTracks the current marketing version
.github/workflows/release-please.yamlCreates release PRs and tags
.github/workflows/deploy-marketing.yamlProduction deploy on marketing@v* tags
apps/marketing/CHANGELOG.mdAuto-generated changelog
apps/marketing/package.jsonVersion field auto-updated

Code Quality Checks

There's also a .github/workflows/check.yml that runs on every push to main and on all pull requests:

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v1
      - run: bun install
      - run: bun run lint
      - run: bun run typecheck

This ensures lint and type errors are caught before code reaches main.

On this page