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 deployProduction 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:
vercel pull— downloads the project settings and environment variables from Vercelvercel build --prod— builds the Next.js app locally in the CI runnervercel 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:
- Go to your Vercel project → Settings → Git
- Under Deploy Hooks, leave empty (we don't use these)
- 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:
- Go to vercel.com/account/tokens
- Create a new token with a descriptive name (e.g. "YeetCode GitHub Actions")
- Scope it to your team if using Vercel Teams
Org ID and Project ID:
- Go to your Vercel project → Settings → General
- Scroll to Project ID — copy it
- 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:
| Secret | Description |
|---|---|
VERCEL_TOKEN | Your Vercel API token |
VERCEL_ORG_ID | Your Vercel team/org ID |
VERCEL_MARKETING_PROJECT_ID | Project 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):
- Go to your Vercel project → Settings → Environment Variables
- Add all required variables (check
apps/marketing/.env.exampleor.env.localfor the list) - Common ones include:
NEXT_PUBLIC_CONVEX_URL— your Convex deployment URLNEXT_PUBLIC_CLERK_PUBLISHABLE_KEY— Clerk publishable keyCLERK_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):
| Secret | Used by | Description |
|---|---|---|
MY_RELEASE_PLEASE_TOKEN | release-please | GitHub PAT for creating release PRs and tags |
CONVEX_DEPLOY_KEY_PRODUCTION | deploy-backend | Convex production deploy key |
VERCEL_TOKEN | deploy-marketing | Vercel API token |
VERCEL_ORG_ID | deploy-marketing | Vercel team/org ID |
VERCEL_MARKETING_PROJECT_ID | deploy-marketing | Production Vercel project ID |
Files Involved
| File | Purpose |
|---|---|
release-please-config.json | Registers the marketing app for versioning |
release-please-manifest.json | Tracks the current marketing version |
.github/workflows/release-please.yaml | Creates release PRs and tags |
.github/workflows/deploy-marketing.yaml | Production deploy on marketing@v* tags |
apps/marketing/CHANGELOG.md | Auto-generated changelog |
apps/marketing/package.json | Version 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 typecheckThis ensures lint and type errors are caught before code reaches main.