Setting and debugging Azure Devops yaml env vars

I received an interesting question yesterday that highlighted how some parts of environment variables in Azure devops are not clear. Here are some things to check if your environment variables aren’t working in azure pipelines.

Check which variable importing method you need

When importing a variable into a step in you devops script you can use env or variables. The env parameter is used when importing variables as secrets from your library. Azure pipelines will avoid printing the values in logs. If you don’t need this facility you can just use the variables section.

Using variables

script: |
  npm install
  npm run build
displayName: 'npm install and build'
variables:
  - name: react.app.api.baseurl
    value: 'test'
  - name: react.app.client.id
    value: '333333'

Using env (Azure Devops will hide the variable contents where possible)

script: |
  npm install
  npm run build
displayName: 'npm install and build'
env:
  REACT_APP_BASEURL: ${variableFromTheLibrary}
  REACT_APP_CLIENT_ID: ${variableFromTheLibrary2}

Understand how devops changes variables names for environment

Azure devops changes your variable names! It’s important to understand this so you know what to reference in your application.

So if I had this script…

script: |
  npm install
  npm run build
displayName: 'npm install and build'
variables:
  - name: react.app.api.baseurl
    value: 'test'
  - name: react.app.client.id
    value: '333333'
env:
  REACT_APP_Gradient: '1'

For the variable names above you would reference these in your app like this.

In index.html:

<div id="test">%REACT_APP_CLIENT_ID%</div>
<div id="gradient">%REACT_APP_GRADIENT%</div>

or in jsx:

<Component>{process.env.REACT_APP_API_BASEURL}</Component>
<Component>{process.env.REACT_APP_GRADIENT}</Component>

So you can see that

  1. The . part is replaced with an underscore _
  2. All parts of the name are made uppercase!

Make sure you prepend the variable with the correct hint

If you’re building a react app with environment variables then you have to get the value injected at build time. React and other libraries kind of use a bit of magic for this. For the magic to work you have to hint to the library which variables are relevant.

For create-react-app apps then you should prepend relevant environment variables with REACT_APP_. Otherwise your variable will not be replaced in the build.

Each library has their own configuration! You should read and understand the library documentation. For example if you’re using gatsby you have to prepend with GATSBY_.

Make sure that the file you are adding variable to is processed by webpack

The environment variables get processed by webpack. In create react app none of the files you place in /public are processed by webpack so the environment variables will not get replaced! You can add variables to index.html and to any of your componenets in the src folder because they are processed by webpack.

If you need to set a variable in a file in /public you would have to use Azure Devops to replace the value. Something like this would replace the value in the file.

npm run build && sed -i 's/$%REACT_APP_ClientId%/$${the.variable.value.inazure.devops.script}/' ./build/public/temp.html

Finally, you can debug if the variables are available as expected

If you’re building on a linux build agent you can use the printenv command to get a list of all the environment variables in the devops script.

You can also use set to get all the environment information. This will also work on windows build agents.

- script: |
    set
    npm install
    npm run build

  displayName: 'npm install and build'
  env:
    REACT_APP_APIBaseUrl: 'test'
    REACT_APP_Client_ID: '333333'

You would see the following output in your logs

REACT_APP_APIBASEURL=test
REACT_APP_CLIENT_ID=333333

You can also debug a step or the entire pipeline

If you set the variable System.Debug to true you will get a full debug stream in the pipeline logs. This includes available environment variables. You can set this at the highest level in your yaml file to debug every step. Or you can add it to the step.

variables:
  - name: System.Debug
    value: true
Darragh ORiordan

Hi! I'm Darragh ORiordan.

I live and work in Sydney, Australia building and supporting happy teams that create high quality software for the web.

I also make tools for busy developers! Do you have a new M1 Mac to setup? Have you ever spent a week getting your dev environment just right?

My Universal DevShell tooling will save you 30+ hours of configuring your Windows or Mac dev environment with all the best, modern shell and dev tools.

Get DevShell here: ✨ https://usemiller.dev/dev-shell


Read more articles like this one...

List of article summaries

#frontend-development

Migrating a Create React App (CRA) application to Vite

I had an existing app that was scaffolded using create react app (CRA) and extended with craco. CRA didn’t support the tooling I needed so I had to look for an alternative. I found Vite.

There are some incredible improvements in Vite over CRA, including PostCSS 8.0 support so I decided to migrate my production application.

I’ll explain some of the benefits of Vite and describe the steps you need to take to upgrade your application.

Update October 2022: I changed @vitejs/plugin-react-refresh to @vitejs/plugin-react. The former is deprecated now.

#frontend-development

Fix React Router navlink-exact when activeClass is not working

If you’re adding navlinks with react router because you want to set the active class you might find that it doesn’t work. These are the steps I had to take to make this work.

#frontend-development

Avoid rebuild of React App in every CI stage

If you have a react app you can use env vars like REACT_APP_MY_ENV_VAR in your application and React will automatically pull them in to your app when you build the production application.

This is very useful but if you have variables that change for each environment and your application build takes a long time, you might want to avoid building unnecessarily in CI. For example you might have a QA environment and a Staging environment that have different configuration.

We type-check our code on each build and that was taking 5 minutes+ to build each environment so we had to make it faster. We changed our app from using REACT_APP env vars to using a configuration file that we could quickly write to using CI.

Our CI system is Azure DevOops so the CI scripts here are specifically for Azure DevOps but they apply to most CI systems with small changes.

The real work happens in a Node.js script that would work anywhere.

Comments