In this post, I will walk you through how you can set up a docker image for your React app. At the end you will have a docker image that can be built and run on any machine that has docker installed without setting up a special development environment.

A sketch of a container with the React logo on it

Pre-requisites

You need to have docker installed on your machine to create a docker image.

Docker can be installed either through Docker Desktop or Docker Engine. In most cases, Docker Desktop is the way to go and you can install it following the instructions on the Docker Desktop page.

Before proceeding to the next step, make sure that you can run the docker command.

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

Note: On Linux, you usually have to run docker as root with sudo. This is because your user will not have access to the Docker service by default. You can optionally follow these instructions to run docker as a non-root user.

Creating a docker image

Create a Dockerfile

Create a new file named Dockerfile at the root of your react project and place the following code in it. (A Dockerfile does not have a file extension)

# syntax=docker/dockerfile:1
FROM node:18-alpine as builder
WORKDIR /home/node/app
COPY . .
RUN npm ci
RUN npm run build

FROM nginx:1.24-alpine as server
COPY --from=builder /home/node/app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf

In a nutshell, this Dockerfile describes a multi-stage build where the builder stage creates a production build of the react app that is then hosted by an nginx container. Check out this post for a more in-depth look at this Dockerfile.

We need to provide a custom configuration to nginx so that it works properly with client-side routing. Place the following configuration into a file named nginx.conf alongside the Dockerfile.

server {
listen 80;
listen [::]:80;

location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
}

The key part of this nginx configuration is the try_files directive which tells nginx to use index.html for all the URLs.

Adjust build output folder

Depending on the build output folder of your project, you might have to change one of the COPY instructions in the Dockerfile. It currently expects the build output to be in the dist folder which is where create-vite places the production builds by default.

COPY --from=builder /home/node/app/dist /usr/share/nginx/html

If you are using Create React App which places the production builds in the build folder by default, you can change the instruction like so.

- COPY --from=builder /home/node/app/dist /usr/share/nginx/html
+ COPY --from=builder /home/node/app/build /usr/share/nginx/html

Add .dockerignore

Add the following to a file named .dockerignore at the root of the project to prevent docker from copying the node_modules and the build output folder (dist). As in the previous step, adjust the build output folder according to your project.

node_modules
dist

Build the image

With the Dockerfile, .dockerignore and nginx.conf files placed at the root of the project, we can build the image with the following command at the same place

$ docker build -t react-app .

You can replace react-app with any name you like but you will then have to use that name in all of the following commands. Don't miss the dot character at the end of the command that refers to the current directory.

Whenever you make changes to your React project, you need to build the image again for it to contain the latest changes.

Running the docker image

You can run the image that we built in the previous step with the following command

$ docker run -p "8000:80" react-app

With this command, we are asking Docker to start a container using the image of the given name and then map port 80 on that container to port 8000 on the host computer. Port 80 is the default port on which nginx serves content. Now you should be able to access your React app on http://localhost:8000.

Screenshot of Chrome running a React app on localhost
React app running on localhost:8000

Next steps

The biggest benefit of docker is being able to run applications without having to manually set up other packages and dependencies. Now if you have a copy of this dockerized project on another machine, you can use the same docker build and run command to start the React app without having to set up Node.js or a web server.

You can also ask Docker to build an image directly from a Github repo that has a Dockerfile in the root folder with the following command.

$ docker build -t react-app "<git-url>#<git-branch>"
Frontend undefined logo