An Environment in GitHub is basically a set of three things:
- Secrets
- Variables
- Protection rules
When you define an environment, you provide a name and can configure any of the above.
For example, when defining an environment named UAT (in Environments tab in repo Settings), the environment definition page would look like this:
What is interesting is that you can reference an environment in a job in a GitHub Actions workflow using an environment block like this:
jobs:
deploy-to-vercel-pr-preview-env:
runs-on: ubuntu-24.04
environment:
name: Preview
url: ${{ steps.deploy-artifacts.outputs.previewUrl }}
In addition to the fact that such a job is allowed to access Variables and Secrets defined within the environment (as opposed to at the repo level) and Protection Rules such as delayed execution, manual approval, and deployment only from branches meeting specified criteria (e.g. with matching names and/or with branch protection rules) apply, when a job references an environment
, this enables a number of other interesting behaviours:
-
There is a really nice sticky comment on the PR (so it updates with every push to the source branch if that triggers the CI workflow) which shows the value of the
url
property for theenvironment
once the job has completed: -
The
url
property ofenvironment
can be static but it can also reference a step output parameter of the same job. In the latter case, theurl
property of theenvironment
block in the job will be evaluated after the step which outputs that parameter value has executed.In the job snippet shown above, the step that produces the referenced step output parameter is:
id: deploy-artifacts run: | previewUrl=$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }}) echo "previewUrl=$previewUrl" >> "$GITHUB_OUTPUT"
Once the job has completed (or perhaps when the step above has completed), value of step output parameter
previewUrl
would be available. This would be assigned tourl
proeprty of theenvironment
. This is what gets displayed on the sticky comment for the environment as the deployment URL -
If a job referencing an environment runs on multiple source branches (in multiple PRs), they don't seem to wait for each other i.e. they seem to run in parallel (I might be wrong on this).
In this case each would post a different URL in its sticky comment as long as the underlying deployment logic generated a different URL on every deployment. For example, every deployment of Next.js project to Preview environment in your Vercel project would generate a new URL.
In fact, since Vercel has such a generous allowance of deployment to an environment that would keep active, all deployments of the same branch, within the same pull request are active and accessible. If your deployment job references a GitHub environment (e.g. "Preview" in above example) then all of these deployment URLs are accessible on the pull request, not just the latest one:
-
All deployments to an environment, with their respective URLs if provided, can also be seen on repo main page in a section on right hand side named Deployments:
You can click an environment name and see a list of all deployments to it, including link to each. The link to the most recent deployment is shown right at the top:
To use GitHub Environments in my Next.js project which I deploy to Vercel, I do the following:
-
Create two GitHub Environments, named Production and Preview.
A Vercel project to which the repo is deployed also has evironments with the same names (these are Vercel environments though, not GitHub environments). So its good to have matching names in both GitHub repo and Vercel project.
-
My CI workflow deploys a pull request's source branch to Vercel's Preview environment and references GitHub Environment named "Preview":
name: CI concurrency: group: ci-${{ github.ref }} cancel-in-progress: true permissions: checks: write pull-requests: write on: pull_request: branches: - main env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} jobs: deploy-to-vercel-preview-env: name: Deploy to Vercel Preview environment runs-on: ubuntu-24.04 environment: name: Preview url: ${{ steps.deploy-artifacts.outputs.previewUrl }} steps: - uses: actions/checkout@v2 - name: Install Vercel CLI run: npm install --global vercel@latest - name: Pull Vercel Environment Information run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} - name: Build Project Artifacts run: vercel build --token=${{ secrets.VERCEL_TOKEN }} - name: Deploy Project Artifacts to Vercel id: deploy-artifacts run: | previewUrl=$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }}) echo "previewUrl=$previewUrl" >> "$GITHUB_OUTPUT"
-
Release/CD workflow that deploys
main
to Vercel Production environment references the GitHub Environment named "Production":
name: Release to Production concurrency: release-to-prod-pipeline on: push: branches: - main jobs: deploy: name: Deploy to Vercel runs-on: ubuntu-24.04 environment: name: Production url: ${{ steps.deploy-artifacts.outputs.previewUrl }} env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} steps: - uses: actions/checkout@v2 - name: Install Vercel CLI run: npm install --global vercel@latest - name: Pull Vercel Environment Information run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} - name: Build Project Artifacts run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} - name: Deploy Project Artifacts to Vercel id: deploy-artifacts run: | previewUrl=$(vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}) echo "previewUrl=$previewUrl" >> "$GITHUB_OUTPUT"
Top comments (0)