DEV Community


Ways to load env variables for your script

・2 min read

Several years ago when I decided to write an article, I got this inject-env-variables-with-no-tears. At that time, I know nothing about makefile and shell script(almost), the only idea in my brain is just Nodejs. Years later, I got new and better solutions.

Firstly, let's talk about what env variables act in software like a project written in Nodejs. Let's say it's an app that is bootstrapped by create-react-app. By default, this app will be served on the root path of a host, like If it's supposed to be served on a sub-path like /apps/my-app, you have to tell the build script what the exact path it is. The way it receives the path value is through the env variable, actually as PUBLIC_URL.
The reason why it(react-scripts) prefers the env variable not an inline argument is env variable is the most unified. Different operations may have different ways in commands, data format, etc. But they all have same basic support for the env variable. That means the great cross-platform. That's it.

Now, let talk about how to inject env variables into the project.

Shell Script

For example, you are going to set an env variable for the app.

Enter fullscreen mode Exit fullscreen mode

Let's create a file named

export PUBLIC_URL=/apps/my-app
/node_modules/.bin/react-scripts build
Enter fullscreen mode Exit fullscreen mode

If there are multiple stacks for deployment, just created more build-[stack-name].sh, tell the build manager(like Jenkins) that executes the correct shell script.


Makefile works like shell script plus tasks.

PATH := ./node_modules/.bin:${PATH}
.PHONY: start build
    react-scripts start
    export PUBLIC_URL=/apps/my-app; \
    react-scripts build
Enter fullscreen mode Exit fullscreen mode

The start and build are tasks (called target by Makefile) defined by the Makefile. In the build target, the first line is to set the PUBLIC_URL. Please be noticed it ends with a semicolon followed by a backslash. This is because each line in a target is executed in a standalone shell by default, which means the env variable set in the first line is not readable by the second line. The sign that a semicolon followed by a backslash asks Makefile that the next line executes in the current shell, which means they share the same context. In this way, the second line receives the env variable.
There is another way to declare that the lines in the target share the same shell, one-shell. It is not available in some old implementations, such as mine. So I still use the old mark. If you have a new Makefile, try yourself if one-shell works.

Why not Nodejs

Compare to Nodejs(usually dot-env or set env manully by process.env[name] = value), shell script works more simple and easy. And the great part is, shell script works for all unix like OS, not only Nodejs. In this point of view, it's sort of cross-platform.

Discussion (0)