Theodore Morgan Consultation Bureau

11/28/2023 (about 1 year ago)

How to use GitHub Actions with Vercel staging branches and Cloudflare DNS powered subdomains

Cover image from TED Vortex
by TED Vortex1 min read engineering CI/CD

Deploying git repositories with Vercel is a great integration with automated builds on push and full support for custom domains.

This can prove to be a challenge if one wants to use a CI/CD environment like, for example, a GitHub Action with Vercel CLI, because, without the git integration, the "git branch" options for any added domain becomes unavailable.

Cover image
Add a beta domain for named preview branches

This is how our frontend release workflow is set up using semantic-release and vercel CLI:

yaml
1name: "Semantic release"
2
3on:
4  push:
5    branches:
6      - main
7      - alpha
8      - beta
9
10concurrency:
11  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
12  group: release-${{ github.ref }}
13  cancel-in-progress: true
14
15jobs:
16  setup:
17    name: Set environment variables
18    runs-on: ubuntu-latest
19    outputs:
20      DEPLOY_ENVIRONMENT: ${{ steps.env.outputs.DEPLOY_ENVIRONMENT }}
21      VERCEL_ENVIRONMENT: ${{ steps.env.outputs.VERCEL_ENVIRONMENT }}
22      VERCEL_COMMAND: ${{ steps.env.outputs.VERCEL_COMMAND }}
23    steps:
24      - name: "☁️ compute environment variables"
25        id: env
26        run: |
27          echo "DEPLOY_ENVIRONMENT=$([[ ${{ github.ref_name }} == 'main' ]] && echo 'production' || echo ${{ github.ref_name }})" >> $GITHUB_OUTPUT
28          echo "VERCEL_ENVIRONMENT=$([[ ${{ github.ref_name }} == 'main' ]] && echo 'production' || echo 'preview')" >> $GITHUB_OUTPUT
29          echo "VERCEL_COMMAND=$([[ ${{ github.ref_name }} == 'main' ]] && echo "--prod" || echo '')" >> $GITHUB_OUTPUT
30
31  release:
32    environment:
33      name: ${{ needs.setup.outputs.DEPLOY_ENVIRONMENT }}
34      url: https://github.com/${{ github.repository }}/releases/tag/${{ steps.semantic-release.outputs.release-tag }}
35    outputs:
36      release-tag: ${{ steps.semantic-release.outputs.release-tag }}
37    name: Semantic release
38    needs:
39      - setup
40    runs-on: ubuntu-latest
41    steps:
42      - name: "☁️ checkout repository"
43        uses: actions/checkout@v4
44        with:
45          fetch-depth: 0
46
47      - name: "🔧 setup node"
48        uses: actions/setup-node@v4
49        with:
50          node-version: 20
51
52      - name: "🔧 install npm@latest"
53        run: npm i -g npm@latest
54
55      - name: "📦 install dependencies"
56        uses: bahmutov/npm-[email protected]
57
58      - name: "🚀 release"
59        id: semantic-release
60        uses: tmcb-space/release@v1
61        env:
62          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63
64  deploy:
65    environment:
66      name: ${{ needs.setup.outputs.DEPLOY_ENVIRONMENT }}
67    name: Deploy to Vercel
68    needs:
69      - setup
70      - release
71    runs-on: ubuntu-latest
72    env:
73      VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
74      VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
75    steps:
76      - name: "☁️ checkout repository"
77        uses: actions/checkout@v4
78        with:
79          fetch-depth: 0
80
81      - name: "🔧 setup node"
82        uses: actions/setup-node@v4
83        with:
84          node-version: 20
85
86      - name: "🔧 install npm@latest vercel@canary"
87        run: npm i -g npm@latest vercel@canary
88
89      - name: "📦 Pull Vercel Environment Information"
90        run: npx vercel pull --yes --environment=${{ needs.setup.outputs.VERCEL_ENVIRONMENT }} --token=${{ secrets.VERCEL_TOKEN }}
91
92      - name: "📦 Pull Vercel Build Environment"
93        run: npx vercel env pull .env.local --token=${{ secrets.VERCEL_TOKEN }}
94
95      - name: "📂 Build Project Artifacts"
96        run: npx vercel build ${{ needs.setup.outputs.VERCEL_COMMAND }} --token=${{ secrets.VERCEL_TOKEN }}
97
98      - name: "🚀 Deploy Project Artifacts to Vercel"
99        run: npx vercel deploy --prebuilt ${{ needs.setup.outputs.VERCEL_COMMAND }} --token=${{ secrets.VERCEL_TOKEN }}

This is great and working as intended, except for the resulting produced deployment URL:

Cover image
Beta branch deploys to tmcb-space-195ydjppl-tmcb.vercel.app

We wanted to make the beta branch deployments always deploy on beta.tmcb.space as seen in the first screenshot and we could make some code changes to do that.

The fastest way to do that is to make use of the Ignored Build Step feature and set it not to build anything:

Cover image
exit 0 disables the build on Vercel

Does this get the job done? Do these minor hacks make it worth not waiting for the official feature to be implemented in Vercel Domains?

For reference, we searched Vercel GitHub issues and discussions for answers and found somewhat ambiguous results, which led us to monkey-patch the problem ourselves. Here are the links if you want to read more:

Written By

Cover image from TED Vortex

TED VortexChief Technical Officer

Has a huge collection of hats spanning 2 decades of experience in software engineering with a clear focus on company growth. Open or closed source, there is no problem not worth solving. Previosly at Snyk and OpenSauced