{"id":64,"date":"2023-06-30T14:14:13","date_gmt":"2023-06-30T04:14:13","guid":{"rendered":"https:\/\/kevinyipeio.com\/blog\/?p=64"},"modified":"2023-06-30T14:46:08","modified_gmt":"2023-06-30T04:46:08","slug":"vercel-how-to-deploy-to-multiple-environments-test-staging-production-more-with-their-own-env-variables-using-github-actions","status":"publish","type":"post","link":"https:\/\/kevinyipeio.com\/blog\/2023\/06\/30\/vercel-how-to-deploy-to-multiple-environments-test-staging-production-more-with-their-own-env-variables-using-github-actions\/","title":{"rendered":"Vercel &#8211; How to deploy to multiple environments (test, staging, production + more) with their own env variables using GitHub Actions"},"content":{"rendered":"\n<p>Vercel is an excellent service to host and deploy your front-end application to. There are a lot of great features such as GitHub integration, monorepo support giving you the option to select a subdirectory to deploy, support for multiple bundling packages, e.g. Parcel, Next.js, Vite, Angular etc. and multiple environments. However, with the latter, it initially seems that it\u2019s only possible to have two environments, Preview and Production (and Development for local dev).<\/p>\n\n\n\n<p>This isn\u2019t entirely true as I will show you in this blog, and I\u2019ll show you how to do it with GitHub Actions (although it isn\u2019t 100% required to use Actions and you can instead use the Vercel CLI if you wish)<\/p>\n\n\n\n<h2>Setup<\/h2>\n\n\n\n<p>In this guide, we will be using Minsu Lee\u2019s (amondnet) GitHub Action for Vercel deployments (see: <a href=\"https:\/\/github.com\/amondnet\/vercel-action\">amondnet\/vercel-action<\/a>). You can create a GitHub Actions workflow using this action as the main step in the workflow. Workflows go in your GitHub repository in the root directory <code>.github\/workflows\/{insert-deploy-workflow-name}.yaml<\/code><\/p>\n\n\n\n<p>Here\u2019s an example from the readme:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>name: Deploy Application\non: &#91;pull_request]\njobs:\n  deploy:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@v2\n      - uses: amondnet\/vercel-action@v20 #deploy\n        with:\n          vercel-token: ${{ secrets.VERCEL_TOKEN }} # Required\n          github-token: ${{ secrets.GITHUB_TOKEN }} #Optional \n          vercel-args: '--prod' #This is what will enable us to have separation of environments\n          vercel-org-id: ${{ secrets.ORG_ID}}  #Required\n          vercel-project-id: ${{ secrets.PROJECT_ID}} #Required \n          working-directory: .\/frontend-app-directory #If you are in a monorepo where you have backend code and frontend code, you can use this to only deploy your frontend code in the sub directory\n          alias-domains: ${{ vars.DOMAIN }} #Domain name for your deployment<\/code><\/pre>\n\n\n\n<p>For the tokens and IDs, you will have to set up an account and project on Vercel and you should be able to find the details in the settings of the project and organisation. If I remember correctly, the vercel-org-id will be known as the \u201cTeam ID\u201d in the organisation settings.<\/p>\n\n\n\n<p>You will put these secrets in GitHub Actions secrets which can be found in your repository settings tab, then find &#8220;Secrets and Variables &gt; Actions&#8221; in the sidebar.<\/p>\n\n\n\n<p>You can find out more details on how to set up by reading the documentation, but what I will focus on is the ability to simulate multiple environments.<\/p>\n\n\n\n<h2>Choose environments using Actions inputs<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>on:\n    workflow_dispatch:\n        inputs: # GitHub Actions inputs will allow you to select environments\n            releaseType:\n                description: 'Release Type'\n                required: true\n                default: 'test'\n                type: choice\n                options:\n                    - test\n                    - staging\n                    - prod<\/code><\/pre>\n\n\n\n<p>You can use \u201cinputs\u201d in your GitHub Actions workflow and refer to it in your action to determine which environment to deploy to. Replace the <code>on:<\/code> property in the previous example with the above. You can then refer to it using <code>${{ inputs.releaseType }}<\/code> and use it in conditionals for environment specific configurations. E.g. <code>vercel-args: ${{ inputs.releaseType == \u2018prod\u2019 &amp;&amp; \u2018--prod\u2019 || \u2018\u2019 }}<\/code><\/p>\n\n\n\n<p>Alternatively, you could have one workflow for each environment.<\/p>\n\n\n\n<h2>Deploying to a chosen environment<\/h2>\n\n\n\n<h4>Environment variables (environment-specific)<\/h4>\n\n\n\n<p>To separate environments, we will first create variables for the GitHub Actions. See the example below:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"1024\" height=\"741\" src=\"https:\/\/kevinyipeio.com\/blog\/wp-content\/uploads\/2023\/06\/image-2-1024x741.png\" alt=\"\" class=\"wp-image-68\" srcset=\"https:\/\/kevinyipeio.com\/blog\/wp-content\/uploads\/2023\/06\/image-2-1024x741.png 1024w, https:\/\/kevinyipeio.com\/blog\/wp-content\/uploads\/2023\/06\/image-2-300x217.png 300w, https:\/\/kevinyipeio.com\/blog\/wp-content\/uploads\/2023\/06\/image-2-768x556.png 768w, https:\/\/kevinyipeio.com\/blog\/wp-content\/uploads\/2023\/06\/image-2.png 1169w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>You can click the green &#8220;New repository variable&#8221; button to create a variable. As you can see in the screenshot I&#8217;ve already created some which will be passed into <code>vercel-args<\/code> property in the GitHub action mentioned earlier. <code>vercel-args<\/code> will be the arguments that are used by the action to insert when running the <code>vercel<\/code> deployment. We can leverage this <code>vercel-args<\/code> attribute of the action to pass in environment-specific environment variables, each variable will be passed in as using the <code>--build-env<\/code> option and then <code>{VARNAME}={value}<\/code> so <code>--build-env {VARNAME}={value}<\/code>. And you can have as many of these options as you want.<\/p>\n\n\n\n<p>To deploy to production, make sure to also add in the <code>--prod<\/code> option to the arguments.<\/p>\n\n\n\n<p>An example would be:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vercel-args: ${{ inputs.releaseType == 'prod' &amp;&amp; vars.PROD_ARGS || inputs.releaseType == 'staging' &amp;&amp; vars.STAGE_ARGS || inputs.releaseType == 'test' &amp;&amp; vars.TEST_ARGS || '' }}<\/code><\/pre>\n\n\n\n<p>This will ensure that the selected environment will get its own environment variables.<\/p>\n\n\n\n<h4>Environment-specific domains<\/h4>\n\n\n\n<p>We will use a similar strategy for environment-specific domains. Ensure that you have set up the CNAME in your DNS provider to point each domain you would like to <code>cname.vercel-dns.com<\/code>. <\/p>\n\n\n\n<p>So for example, in your Domain Name, let&#8217;s say, <code>company.com<\/code>, you can add a CNAME record for <code>test.company.com<\/code> by going into the DNS records for <code>company.com<\/code> and adding a CNAME record<\/p>\n\n\n\n<p>To pass in the domain, we will use the <code>alias-domains<\/code> property of the GitHub Action. You can put the domain name as a hardcoded string in the workflow, or alternatively create a repository variable (which is recommended as you can change it easily).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>alias-domains: ${{ inputs.releaseType == 'prod' &amp;&amp; 'app.company.com' || inputs.releaseType == 'staging' &amp;&amp; 'app.stage.company.com' || inputs.releaseType == 'test' &amp;&amp; 'app.test.company.com' || '' }}<\/code><\/pre>\n\n\n\n<p>Or with GitHub variables:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>alias-domains: ${{ inputs.releaseType == 'prod' &amp;&amp; vars.PROD_DOMAIN || inputs.releaseType == 'staging' &amp;&amp; vars.STAGE_DOMAIN || inputs.releaseType == 'test' &amp;&amp; vars.TEST_DOMAIN || '' }}<\/code><\/pre>\n\n\n\n<h2>Complete example<\/h2>\n\n\n\n<p>Here&#8217;s a complete example, combining all the parts for a workflow:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>name: Deploy Application\non:\n    workflow_dispatch:\n        inputs: # GitHub Actions inputs will allow you to select environments\n            releaseType:\n                description: 'Release Type'\n                required: true\n                default: 'test'\n                type: choice\n                options:\n                    - test\n                    - staging\n                    - prod\n    pull_request: #This is to automatically deploy on a pull request\n        branches:\n            - main\n        paths:\n            - 'frontend-app\/**'\n    push: #This is to automatically deploy on a push to main\n        branches:\n            - main\n        paths:\n            - 'frontend-app\/**'\njobs:\n  deploy:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@v2\n      - uses: amondnet\/vercel-action@v20 #deploy\n        with:\n          vercel-token: ${{ secrets.VERCEL_TOKEN }} <em>#Required<\/em>\n          github-token: ${{ secrets.GITHUB_TOKEN }} #Optional \n         <strong> vercel-args: ${{ inputs.releaseType == 'prod' &amp;&amp; vars.PROD_ARGS || inputs.releaseType == 'staging' &amp;&amp; vars.STAGE_ARGS || inputs.releaseType == 'test' &amp;&amp; vars.TEST_ARGS || '' }} <em>#Environment Specific Arguments<\/em><\/strong>\n          vercel-org-id: ${{ secrets.ORG_ID }}  #Required\n          vercel-project-id: ${{ secrets.PROJECT_ID }} #Required \n          working-directory: .\/frontend-app\n          <strong>alias-domains: ${{ inputs.releaseType == 'prod' &amp;&amp; vars.PROD_DOMAIN || inputs.releaseType == 'staging' &amp;&amp; vars.STAGE_DOMAIN || inputs.releaseType == 'test' &amp;&amp; vars.TEST_DOMAIN || '' }} <em>#Environment Specific Alias Domain<\/em><\/strong><\/code><\/pre>\n\n\n\n<p>See bolded code for the main blocks that make the multiple environment deployments work.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Vercel is an excellent service to host and deploy your front-end application to. There are a lot of great features<a class=\"more-link\" href=\"https:\/\/kevinyipeio.com\/blog\/2023\/06\/30\/vercel-how-to-deploy-to-multiple-environments-test-staging-production-more-with-their-own-env-variables-using-github-actions\/\"><span data-hover=\"Read More\">Read More<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":84,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[10],"tags":[19,20,14,15,17,18,16],"_links":{"self":[{"href":"https:\/\/kevinyipeio.com\/blog\/wp-json\/wp\/v2\/posts\/64"}],"collection":[{"href":"https:\/\/kevinyipeio.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kevinyipeio.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kevinyipeio.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kevinyipeio.com\/blog\/wp-json\/wp\/v2\/comments?post=64"}],"version-history":[{"count":16,"href":"https:\/\/kevinyipeio.com\/blog\/wp-json\/wp\/v2\/posts\/64\/revisions"}],"predecessor-version":[{"id":90,"href":"https:\/\/kevinyipeio.com\/blog\/wp-json\/wp\/v2\/posts\/64\/revisions\/90"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kevinyipeio.com\/blog\/wp-json\/wp\/v2\/media\/84"}],"wp:attachment":[{"href":"https:\/\/kevinyipeio.com\/blog\/wp-json\/wp\/v2\/media?parent=64"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kevinyipeio.com\/blog\/wp-json\/wp\/v2\/categories?post=64"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kevinyipeio.com\/blog\/wp-json\/wp\/v2\/tags?post=64"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}