github-actions

GitHub Actions Deploy to Vercel

GitHub Actions workflow to deploy a frontend application to Vercel with preview deployments on PRs and production on merge.

Overview

A GitHub Actions workflow that deploys your application to Vercel. Creates preview deployments for pull requests and promotes to production when code is merged to the main branch. Uses the Vercel CLI for full control over the deployment process.

Configuration

# .github/workflows/deploy-vercel.yml

name: Deploy to Vercel

on:
  push:
    branches: [main]                   # Production deploy on merge to main
  pull_request:
    branches: [main]                   # Preview deploy on PRs

# Cancel in-progress deployments for the same ref
concurrency:
  group: deploy-${{ github.ref }}
  cancel-in-progress: true

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

jobs:
  deploy:
    runs-on: ubuntu-latest

    environment:
      name: ${{ github.event_name == 'push' && 'production' || 'preview' }}
      url: ${{ steps.deploy.outputs.url }}

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm                   # Cache npm dependencies

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test -- --ci

      - name: Install Vercel CLI
        run: npm install -g vercel

      # Pull Vercel project settings
      - name: Pull Vercel environment
        run: vercel pull --yes --environment=${{ github.event_name == 'push' && 'production' || 'preview' }} --token=${{ secrets.VERCEL_TOKEN }}

      # Build the project using Vercel's build system
      - name: Build project
        run: vercel build ${{ github.event_name == 'push' && '--prod' || '' }} --token=${{ secrets.VERCEL_TOKEN }}

      # Deploy to Vercel
      - name: Deploy to Vercel
        id: deploy
        run: |
          URL=$(vercel deploy --prebuilt ${{ github.event_name == 'push' && '--prod' || '' }} --token=${{ secrets.VERCEL_TOKEN }})
          echo "url=$URL" >> "$GITHUB_OUTPUT"

      # Comment preview URL on pull request
      - name: Comment PR with preview URL
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `🚀 Preview deployment ready: ${{ steps.deploy.outputs.url }}`
            })

Key Options Explained

  • concurrency — Cancels any in-progress deployment for the same branch when a new commit is pushed, preventing wasted resources on stale deploys.
  • environment — Creates GitHub environment deployments with tracked URLs. Shows deployment status directly on PRs and the repository homepage.
  • vercel pull — Downloads project configuration and environment variables from Vercel. The --environment flag selects the right variable set.
  • vercel build --prebuilt — Builds locally in CI, then deploys the pre-built output. Gives you full control over the build environment.
  • --prod flag — Only used on pushes to main. Without it, Vercel creates a preview deployment with a unique URL.

Common Modifications

  • Skip deploy on docs changes: Add paths-ignore: ['**.md', 'docs/**'] to the push trigger to avoid deploying on documentation-only changes.
  • Environment variables: Add vercel env pull .env.local --token=${{ secrets.VERCEL_TOKEN }} to pull env vars before building.
  • Monorepo: Add --cwd packages/frontend to Vercel commands to target a specific workspace package.
  • Protected production: Use GitHub environment protection rules to require approval before production deployments.
  • Alias domains: Add vercel alias $URL my-app-pr-${{ github.event.number }}.vercel.app --token=${{ secrets.VERCEL_TOKEN }} for readable preview URLs.