- Published on
Using Different .env files with create-react-app and Docker
- Authors
- Name
- Yair Mark
- @yairmark
The Issue
React projects that are built with create-react-app
have support for .env
files by default. This setup also allows different configurations to be used for different environments. In my project I had an .env.production
file that looked like the following:
PUBLIC_URL=ui
port=3001
I also had a .env.local
file that looked as follows:
PUBLIC_URL=
port=3001
This properties file controls which port React will use as well as what to prefix all routes with. With the production properties, all routes would be prefixed with ui/
.
The problem was I needed this only in production but not for local builds and dev. So if I ran npm run build
locally I did not want the PUBLIC_URL
to have any value. I wanted this run from inside a docker container so that I could easily run all the pieces of my app together and I had a makefile to simplify this whole process.
After some digging I found that create-react-app
allows environment specific config by creating environment specific files where the file name for a specific environment is basically .env.${NODE_ENV}
. For example production is .env.production
. This page describes exactly which .env
files can be used as well as the order of precedence.
Ok, awesome so I simply need to override NODE_ENV when I run the build in the dockerfile locally:
NODE_ENV=local npm run build
But this did not work :/
Overriding .env files with Create-react-app
After reading the create-react-app documentation more carefully I noticed this line which I had missed:
You cannot override NODE_ENV manually. This prevents developers from accidentally deploying a slow development build to production.
This explained my issue. I dug around a bit more and found out about the tool env-cmd which lets you override this behaviour in react where I simply change the above command to:
cmd-env .env.local npm run build
I went into my build directory and used python SimpleServer to test if it worked:
python -m http.server 3002
When I hit the page I got a blank screen and on looking at the network panel I noticed that I was getting 404's as the app was trying to use a PUBLIC_URL
of ui
despite the fact that my .env.local
had nothing for this. It seems like it merges values if they are empty. I looked through the env-cmd
file and settled on using an .env-cmdrc
file instead which looked as follows:
{
"local": {},
"production": {
"PUBLIC_URL": "ui",
"PORT": "3002"
}
}
I then simply run the following command:
cmd-env local npm run build
After checking using python's simple server I confirmed this approach worked perfectly when using local and when using production as parameters.
Passing the Environment to be Used to a Dockerfile
On the Docker side, I now need to pass this environment variable in and get the dockerfile to use it at build time. To pass the environment variable in I updated my dockerfile as follows:
...
ARG env
ENV environment=$env
RUN echo "---------------env ${environment}"
...
RUN cd /root/my-ui && \
env-cmd ${environment} npm install && \
env-cmd ${environment} npm run build
...
Docker allows you to pass environment variables using a command similar to the below:
docker build --build-arg env=local -t your.domain.com/yourOrg/project:latest . -f ./path/to/Dockerfile
Passing an Environment Variable to a Makefile
Finally I updated my makefile to set the environment to production
by default but allow it to be overridden as follows:
...
ENVIRONMENT?=production
...
docker-build-app-1: ## Build the app1's docker images
docker build --build-arg env=local -t your.domain.com/yourOrg/project:latest . -f ./path/to/Dockerfile
Now if I run make docker-build-app-1
it will use production
as the default environment. To use another environment I pass in an updated environment variable to the makefile as follows:
make docker-build-app-1 ENVIRONMENT=local