# CI/CD Pipelines for Vercel Deployment with GitHub Actions: Automating VitePress Builds in datawhalechina/easy-vibe

> Automate VitePress builds for Vercel deployment with GitHub Actions. Learn how datawhalechina/easy-vibe uses dual CI/CD pipelines for seamless, consistent deployments across Vercel and GitHub Pages.

- Repository: [Datawhale/easy-vibe](https://github.com/datawhalechina/easy-vibe)
- Tags: how-to-guide
- Published: 2026-05-10

---

**The datawhalechina/easy-vibe repository implements dual CI/CD pipelines for Vercel deployment with GitHub Actions by running parallel build processes—leveraging Vercel's native Git integration for automatic production hosting while using GitHub Actions to generate identical artifacts for GitHub Pages, ensuring consistent deployments across platforms through shared configuration files.**

The datawhalechina/easy-vibe project demonstrates a production-grade approach to CI/CD pipelines for Vercel deployment with GitHub Actions using a VitePress documentation site. This setup maintains two synchronized build pathways that trigger on every push to the `main` branch, guaranteeing that static assets remain identical regardless of whether they serve from Vercel's edge network or GitHub Pages.

## Understanding the Dual Pipeline Architecture

The project employs two complementary deployment mechanisms that execute the same build logic but target different hosting platforms.

**Vercel Auto-Deployment** handles production traffic by detecting pushes to connected branches, reading build instructions from [`vercel.json`](https://github.com/datawhalechina/easy-vibe/blob/main/vercel.json), and executing `npm run build`. The platform automatically serves static files from `docs/.vitepress/dist` at the assigned `*.vercel.app` domain.

**GitHub Actions Workflow** (defined in [`.github/workflows/deploy.yml`](https://github.com/datawhalechina/easy-vibe/blob/main/.github/workflows/deploy.yml)) provides an alternative hosting path for organizations requiring GitHub-only environments. This pipeline builds the site using identical commands, archives the output as a Pages artifact, and deploys to GitHub Pages using the official `actions/deploy-pages@v4` action.

Both pipelines share Node.js 20, npm dependency resolution, and the `docs/.vitepress/dist` output directory, ensuring build parity across platforms.

## Configuring Vercel with vercel.json

The root-level [`vercel.json`](https://github.com/datawhalechina/easy-vibe/blob/main/vercel.json) file instructs the Vercel platform on build orchestration, framework detection, and security policies.

```json
{
  "buildCommand": "npm run build",
  "installCommand": "npm install",
  "framework": "vitepress",
  "outputDirectory": "docs/.vitepress/dist",
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        { "key": "X-Content-Type-Options", "value": "nosniff" },
        { "key": "X-Frame-Options", "value": "DENY" },
        { "key": "X-XSS-Protection", "value": "1; mode=block" },
        { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
        { "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=()" }
      ]
    },
    {
      "source": "/sitemap.xml",
      "headers": [{ "key": "Cache-Control", "value": "public, max-age=86400, s-maxage=86400" }]
    },
    {
      "source": "/robots.txt",
      "headers": [{ "key": "Cache-Control", "value": "public, max-age=86400, s-maxage=86400" }]
    }
  ]
}

```

This configuration specifies the **VitePress framework** preset, directs Vercel to run `npm install` followed by `npm run build`, and serves content from the VitePress default output directory. The headers array implements security hardening including content-type sniffing protection, clickjacking prevention via `X-Frame-Options: DENY`, and API permission restrictions.

## GitHub Actions Workflow Implementation

The [`.github/workflows/deploy.yml`](https://github.com/datawhalechina/easy-vibe/blob/main/.github/workflows/deploy.yml) file defines a two-stage pipeline that mirrors the Vercel build process while targeting GitHub Pages infrastructure.

### Build Job Configuration

The build job validates the repository owner before execution to prevent accidental deployments from forked repositories.

```yaml
build:
  if: github.repository_owner == 'datawhalechina'
  runs-on: ubuntu-latest
  steps:
    - name: Checkout
      uses: actions/checkout@v4
      with:
        fetch-depth: 0
    - name: Setup Node
      uses: actions/setup-node@v4
      with:
        node-version: 20
        cache: npm
    - name: Install dependencies
      run: npm ci
    - name: Build with VitePress
      run: npm run build
    - name: Upload artifact
      uses: actions/upload-pages-artifact@v3
      with:
        path: docs/.vitepress/dist

```

This job checks out the repository with full Git history, configures Node.js 20 with npm caching, installs dependencies using `npm ci` for deterministic builds, executes `npm run build`, and uploads the resulting `docs/.vitepress/dist` directory as a deployment artifact.

### Deploy Job Configuration

The deployment stage requires the build job to complete successfully and utilizes GitHub's OpenID Connect permissions for secure Pages publishing.

```yaml
deploy:
  environment:
    name: github-pages
    url: ${{ steps.deployment.outputs.page_url }}
  needs: build
  runs-on: ubuntu-latest
  steps:
    - name: Deploy to GitHub Pages
      id: deployment
      uses: actions/deploy-pages@v4

```

The `actions/deploy-pages@v4` action handles the atomic publication to GitHub Pages, making the site available at `https://datawhalechina.github.io/easy-vibe/` while preserving the build artifacts for rollback purposes.

## Runtime Environment Detection

The VitePress configuration in `docs/.vitepress/config.mjs` implements runtime logic to detect the hosting platform and adjust the base URL and site metadata accordingly.

```js
// Detect Vercel or EdgeOne environments
const isVercel = process.env.VERCEL === '1' || !!process.env.VERCEL_URL
const isEdgeOne = !!process.env.EDGEONE || process.env.EDGEONE === '1'

// Choose the correct base path
const base = process.env.BASE || (isVercel || isEdgeOne ? '/' : '/easy-vibe/')

```

When executing on Vercel infrastructure, the presence of `process.env.VERCEL` or `process.env.VERCEL_URL` triggers the root base path (`/`). In GitHub Actions or local development environments, the configuration defaults to `/easy-vibe/` to accommodate GitHub Pages repository path requirements.

The configuration also dynamically resolves the public site URL for SEO meta tags:

```js
const getSiteUrl = () => {
  if (isVercel && process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`
  if (isEdgeOne && process.env.EDGEONE_URL) return `https://${process.env.EDGEONE_URL}`
  if (process.env.SITE_URL) return process.env.SITE_URL
  return 'https://datawhalechina.github.io/easy-vibe'
}

```

This ensures that sitemap generation, canonical URLs, and OpenGraph meta tags reference the correct domain regardless of which CI/CD pipeline executed the build.

## Security Headers and Caching Optimization

The [`vercel.json`](https://github.com/datawhalechina/easy-vibe/blob/main/vercel.json) configuration injects comprehensive security headers that apply to Vercel deployments:

- **X-Content-Type-Options: nosniff** prevents MIME-type sniffing attacks
- **X-Frame-Options: DENY** blocks clickjacking attempts via iframe embedding
- **X-XSS-Protection: 1; mode=block** enables browser XSS filters
- **Referrer-Policy: strict-origin-when-cross-origin** controls referrer information leakage
- **Permissions-Policy** restricts access to sensitive device APIs including camera, microphone, and geolocation

Static assets like [`sitemap.xml`](https://github.com/datawhalechina/easy-vibe/blob/main/sitemap.xml) and [`robots.txt`](https://github.com/datawhalechina/easy-vibe/blob/main/robots.txt) receive explicit cache-control directives (`public, max-age=86400`) optimizing CDN distribution and search engine crawling efficiency.

## Summary

- **Dual pipeline approach**: The repository implements CI/CD pipelines for Vercel deployment with GitHub Actions by running parallel build processes—Vercel handles automatic production hosting while GitHub Actions provides GitHub Pages previews using identical build configurations.
- **Shared build configuration**: Both pipelines execute `npm run build` and output to `docs/.vitepress/dist`, ensuring deployment consistency across hosting platforms.
- **Environment-aware routing**: The `docs/.vitepress/config.mjs` file dynamically selects base paths (`/` vs `/easy-vibe/`) by inspecting `VERCEL`, `VERCEL_URL`, and `BASE` environment variables at build time.
- **Security hardening**: The [`vercel.json`](https://github.com/datawhalechina/easy-vibe/blob/main/vercel.json) file defines HTTP security headers including `X-Frame-Options`, `X-Content-Type-Options`, and `Permissions-Policy` directives.
- **Access control**: The GitHub Actions workflow includes repository owner validation (`github.repository_owner == 'datawhalechina'`) to prevent unauthorized deployments from forked repositories.

## Frequently Asked Questions

### How does the project detect whether it's running on Vercel versus GitHub Actions?

The `docs/.vitepress/config.mjs` file checks for the presence of `process.env.VERCEL` or `process.env.VERCEL_URL` to identify Vercel's build environment. When these variables exist, the configuration sets the base path to `/`; otherwise, it defaults to `/easy-vibe/` for GitHub Pages compatibility. This detection occurs at build time, ensuring that generated links and asset paths match the intended hosting platform.

### Why maintain both Vercel and GitHub Actions pipelines instead of using just one?

The dual approach provides deployment flexibility and redundancy. Vercel offers automatic deployments with preview URLs and edge network distribution, while GitHub Actions enables hosting within the GitHub ecosystem for organizations with Vercel restrictions or for contributors who cannot access the Vercel project. Both pipelines execute the same build steps defined in [`package.json`](https://github.com/datawhalechina/easy-vibe/blob/main/package.json), guaranteeing identical output regardless of the hosting target.

### What Node.js version does the CI/CD pipeline use?

The workflow specifies Node.js 20 in [`.github/workflows/deploy.yml`](https://github.com/datawhalechina/easy-vibe/blob/main/.github/workflows/deploy.yml) through the `actions/setup-node@v4` action with `node-version: 20`. This matches the environment constraints documented in the project's [`package.json`](https://github.com/datawhalechina/easy-vibe/blob/main/package.json) and ensures compatibility with modern VitePress features and security updates.

### How are security headers applied when deploying through GitHub Actions?

The security headers defined in [`vercel.json`](https://github.com/datawhalechina/easy-vibe/blob/main/vercel.json) apply specifically to Vercel-hosted deployments. When deploying to GitHub Pages via GitHub Actions, the headers depend on the GitHub Pages server configuration. However, the [`vercel.json`](https://github.com/datawhalechina/easy-vibe/blob/main/vercel.json) remains the source of truth for security policies, and organizations using GitHub Pages Enterprise can implement equivalent headers through their CDN or repository settings to match the Vercel configuration.