The integration of Vercel with GitHub has evolved from a simple automated webhook trigger into a sophisticated, programmable deployment pipeline. While Vercel’s native Git integration offers seamless, zero-configuration deployments for standard use cases, modern engineering teams often require granular control over the build process, testing strategies, and deployment triggers. By leveraging GitHub Actions, developers can construct robust Continuous Integration and Continuous Deployment (CI/CD) pipelines that decouple the build logic from the hosting platform, enabling pre-deployment testing, conditional deployments, and automated reporting. This approach addresses the critical gap between local development environments and fully deployed production APIs, ensuring that code passes rigorous validation before it reaches the edge network.
The Case for GitHub Actions Over Native Integration
The default Vercel for GitHub integration is designed for simplicity. It automatically deploys GitHub projects, providing Preview Deployment URLs and automatic Custom Domain updates. However, this black-box approach limits the ability to intervene in the build process. For teams that require custom build steps, local testing against deployed artifacts, or conditional deployment logic, the native integration is insufficient.
To utilize GitHub Actions as the primary deployment mechanism, the native Vercel Git integration must be explicitly disabled. This prevents duplicate deployments and ensures that the GitHub Actions workflow is the sole authority for triggering builds. This configuration is achieved through the @vercel/config package, which allows developers to define project settings in code.
The following configuration snippets demonstrate how to disable automatic deployments. The first example uses a TypeScript configuration file (vercel.ts), while the second uses the traditional JSON format (vercel.json). Note that the github.enabled property is deprecated and should be replaced with git.deploymentEnabled.
```typescript
import type { VercelConfig } from '@vercel/config/v1';
export const config: VercelConfig = {
public: false,
git: {
deploymentEnabled: false,
},
};
```
json
{
"public": false,
"git": {
"deploymentEnabled": false
}
}
With deploymentEnabled set to false, Vercel will no longer automatically trigger builds on git pushes. This silence is necessary to allow the GitHub Actions workflow to take over the deployment lifecycle.
Permissions and Security Configuration
Integrating GitHub Actions with Vercel requires precise permission scopes to function correctly. When connecting a GitHub repository to Vercel, the platform requests specific permissions to facilitate the deployment experience. Understanding these permissions is crucial for security and operational clarity.
At the repository level, Vercel requires the following permissions:
- Web Hooks: Allows Vercel to react to various GitHub events.
- Commit Statuses: Allows synchronization of commit status between GitHub and Vercel.
- Actions: Allows agents to read workflow run logs to help diagnose CI failures. This is a read-only permission.
- Workflows: Allows agents to configure and update CI workflow files on behalf of the user.
At the organization level, Vercel requests:
- Members: Allows Vercel to offer a better team onboarding experience by reading member information.
At the user level:
- Email addresses: Allows Vercel to associate an email with a GitHub account.
These permissions are used to provide the best possible deployment experience. If a user needs to sign up on Vercel with a different GitHub account, they must sign out of their current GitHub account and restart the Vercel signup process. When creating a new project from a GitHub repository or connecting an existing project, these specific permissions are required.
Core GitHub Actions Deployment Strategies
There are two primary methods for deploying to Vercel via GitHub Actions: using the official vercel-action or using the community-driven deploy-to-vercel-action. Each offers different levels of customization and control.
The Official Vercel Action
The amondnet/vercel-action (often referenced as the official or standard Vercel action in documentation) is widely used for its stability and direct integration with the Vercel CLI. It is ideal for standard deployments where the primary goal is to push code to Vercel with minimal configuration.
A typical workflow using this action involves checking out the code, caching dependencies, setting up the Node environment, building the project, and then deploying. The action outputs a preview-url, which is critical for running tests against the deployed environment.
The following workflow demonstrates a strategy where tests are run locally, the application is deployed to a staging environment, tests are run against the staging URL, and finally, the application is deployed to production if the push is to the main branch.
```yaml
name: Deploy CI
on:
push:
branches: [main]
pull_request:
types: [opened, synchronize, reopened]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Cache Dependencies
uses: actions/cache@v1
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: ${{ runner.os }}-node-
- name: Setup Node 14
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Build
run: |
yarn install --frozen-lockfile
npm run bundle
- name: Run Tests Locally
run: npm run test
- name: Deploy to Staging
id: deploy-vercel-staging
uses: amondnet/vercel-action@v20
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID_TL_ENGINE }}
scope: ${{ secrets.VERCEL_ORG_ID }}
- name: Run Tests Against Vercel
env:
VERCEL_URL: ${{ steps.deploy-vercel-staging.outputs.preview-url }}
run: npm run test
- name: Deploy to Production
uses: amondnet/vercel-action@v20
id: deploy-vercel-production
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID_TL_ENGINE }}
vercel-args: '--prod'
scope: ${{ secrets.VERCEL_ORG_ID }}
```
This workflow highlights the importance of verifying deployments. Running tests against the preview-url ensures that the deployed artifact behaves as expected in the live environment, bridging the chasm between local machine tests and production reality.
The Deploy-to-Vercel Action for Advanced Control
For teams requiring more customization than the official action provides, the BetaHuhn/deploy-to-vercel-action offers enhanced features. This action supports more granular control over when to deploy, allowing developers to trigger deployments on every commit, only on new releases, or even on a cron schedule. It also supports deploying every Pull Request (PR) and commenting on it with a custom preview URL.
Key features of this action include:
- Use GitHub Actions events to control when to deploy to Vercel.
- Automatically deploy every pull request.
- Comment on pull requests with a preview link.
- Create a deployment on GitHub.
- Assign custom dynamic domains to each deployment or PR.
- Can deploy Dependabot PRs and optionally even PRs made from forks.
The following workflow demonstrates how to use this action to deploy on push to master and on pull request events, while skipping deployments if the commit message contains [skip ci]. It also includes a step to create a comment on the PR with the preview and inspector URLs.
```yaml
name: Deploy CI
on:
push:
branches: [master]
pull_request:
types: [opened, synchronize, reopened]
jobs:
deploy:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip ci]')"
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Deploy to Vercel Action
id: vercel-deploy
uses: BetaHuhn/deploy-to-vercel-action@v1
with:
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
CREATE_COMMENT: false
- uses: phulsechinmay/[email protected]
if: ${{ steps.vercel-deploy.outputs.DEPLOYMENT_CREATED }}
with:
message: |
This pull request has been deployed to Vercel.
<table>
<tr>
<td><strong>✅ Preview:</strong></td>
<td><a href='${{ steps.vercel-deploy.outputs.PREVIEW_URL }}'>${{ steps.vercel-deploy.outputs.PREVIEW_URL }}</a></td>
</tr>
<tr>
<td><strong>🔍 Inspect:</strong></td>
<td><a href='${{ steps.vercel-deploy.outputs.DEPLOYMENT_INSPECTOR_URL }}'>${{ steps.vercel-deploy.outputs.DEPLOYMENT_INSPECTOR_URL }}</a></td>
</tr>
</table>
[View Workflow Logs](${{ steps.vercel-deploy.outputs.LOG_URL }})
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COMMENT_IDENTIFIER: 'vercel-deploy'
```
In this workflow, the CREATE_COMMENT is set to false in the deploy action, and instead, a separate action (phulsechinmay/rewritable-pr-comment) is used to post a formatted comment. This allows for more complex message formatting and conditional logic. The if condition checks if a deployment was created before posting the comment.
Reacting to Deployment Status with repository_dispatch
A powerful feature of the Vercel-GitHub integration is the ability for Vercel to send repository_dispatch events to GitHub when the status of a deployment changes. These events can trigger GitHub Actions, enabling continuous integration tasks that depend on the outcome of a Vercel deployment. This is particularly useful for post-deployment validation, notification systems, or triggering downstream processes.
GitHub Actions can be configured to listen to the following repository_dispatch events:
vercel.deployment.readyvercel.deployment.successvercel.deployment.errorvercel.deployment.canceled(canceled as a result of the ignored build script)vercel.deployment.ignored(canceled as a result of automatic deployment skipping, e.g., in monorepos where unaffected projects are skipped)vercel.deployment.skippedvercel.deployment.pendingvercel.deployment.failedvercel.deployment.promoted
These events contain a JSON payload with information about the deployment, such as the deployment url and deployment environment. GitHub Actions can access this payload through github.event.client_payload.
To test the workflow prior to merging to main, it is recommended to add a workflow_dispatch trigger. This allows manual triggering of the workflow for testing purposes.
yaml
on:
repository_dispatch:
types:
- 'vercel.deployment.ready'
- 'vercel.deployment.success'
- 'vercel.deployment.error'
- 'vercel.deployment.canceled'
- 'vercel.deployment.ignored'
- 'vercel.deployment.skipped'
- 'vercel.deployment.pending'
- 'vercel.deployment.failed'
- 'vercel.deployment.promoted'
By leveraging these events, teams can build robust feedback loops where the state of the deployment directly influences subsequent CI/CD steps. For example, a failure event could trigger a Slack notification or a rollback procedure.
Conclusion
Integrating Vercel with GitHub Actions transforms the deployment process from a passive occurrence into an active, controllable engineering workflow. By disabling the native Git integration and adopting a GitHub Actions-driven approach, teams gain the ability to insert custom build steps, run comprehensive tests against staging environments, and conditionally deploy to production. The use of repository_dispatch events further enhances this pipeline by allowing GitHub Actions to react to the specific outcomes of Vercel deployments, enabling advanced automation and monitoring. Whether using the official vercel-action for simplicity or deploy-to-vercel-action for granular control, the combination of Vercel and GitHub Actions provides a powerful foundation for modern, reliable, and efficient CI/CD practices.