CI/CD Pipelines for Vercel Deployment with GitHub Actions: Automating VitePress Builds in datawhalechina/easy-vibe
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, 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) 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 file instructs the Vercel platform on build orchestration, framework detection, and security policies.
{
"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 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.
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.
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.
// 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:
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 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 and 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 buildand output todocs/.vitepress/dist, ensuring deployment consistency across hosting platforms. - Environment-aware routing: The
docs/.vitepress/config.mjsfile dynamically selects base paths (/vs/easy-vibe/) by inspectingVERCEL,VERCEL_URL, andBASEenvironment variables at build time. - Security hardening: The
vercel.jsonfile defines HTTP security headers includingX-Frame-Options,X-Content-Type-Options, andPermissions-Policydirectives. - 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, 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 through the actions/setup-node@v4 action with node-version: 20. This matches the environment constraints documented in the project's 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 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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →