In this post, I will walk you through how you can use docker to set up a development environment for a React project.

A sketch of the Docker whale carrying flasks with the React icon on them

What is Docker?

Docker is a containerization platform that allows us to create isolated containers to run our code in. We can pack all the dependencies needed for the code to run into a container image which can then be used to run on any machine that has docker installed with no special setup. I have written about how you can dockerize a React app for deployment in this post.

Why should you use Docker to set up the environment?

By using docker to set up the development environment, you will be able to start working on a project with just a few commands instead of spending hours getting the tools to work on new machines or new OSes.

Moreover, if you need to work on multiple projects at the same time, it can be quite tedious to set up and maintain several development environments. Especially if the projects have conflicting requirements such as different versions of Node.js. By running the development environments inside Docker containers, the environments will not interfere with each other and you can switch between them quite easily.

Pre-requisites

You need to have Docker installed on your computer to create and run Docker images and containers. You can install Docker Desktop by following the instructions here.

Make sure that you can run the docker command before moving on to the next step

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

Overview of the setup

To set up the development environment, we will first create a docker image containing Node.js that is capable of starting the development server for the project.

To create this docker image, we need to

Once the image has been built, we can ask Docker to create a container with it so that we can run development commands on it. To access the dev server from the host machine, we will publish the port on which the dev server is running.

To allow the dev server to keep track of the changes to the code on the host machine, we will also use a bind mount to "share" the source code folder on the host machine with the container.

You can find some of the limitations of this setup in the notes section.

Setting up a development environment for a create-react-app project

Place the following code into a file named Dockerfile at the root of your project. (Note: A Dockerfile has no file extension) If you already have a Dockerfile for deploying your React app, you can name it Dockerfile.develop.

# syntax=docker/dockerfile:1
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN npm i
ENTRYPOINT ["npm"]

Place the following into a .dockerignore file and place it alongside the Dockerfile.

node_modules

Now you can run the docker build command to build the image. react-app is the name or "tag" that will be assigned to the image, you can use whichever name you like. Don't miss the dot at the end of this command.

$ docker build -t react-app .

If you used a different name for the Dockerfile such as Dockerfile.deploy, you need to specify this in the build command with -f flag like so,

$ docker build -t react-app -f Dockerfile.develop .

Once you have built the image, you can start a container and run commands in it with a docker run command. By default, you start the dev server on a create-react-app project with the npm start command. You can now run the same command like so and the dev server will be accessible at http://localhost:3000.

$ docker run -p "3000:3000" react-app start

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

With the above command, the dev server will not update when the code is changed on the host machine. To fix this, we can use a bind mount with the -v flag to mount the source code folder inside the container.

$ docker run -p "3000:3000" -v "$(pwd)/src:/app/src" react-app start

This command assumes that you follow the create-react-app convention of storing the .js/.jsx/.ts/.tsx files in the src folder. If you use a different convention in your project, you need to replace /src in the path that is passed to the -v flag (e.g. -v "$(pwd)"/source:/app/source). You can also use multiple -v flags to share several folders.

Adjustments for a Vite project

If you are using Vite, you should need to follow the same process as above but with a few changes.

The Vite dev server is not accessible from the local network by default. Docker can only publish ports that are accessible from the local network of the container. To overcome this, adjust the vite configuration in the vite.config.js so that the dev server is accessible from the local network.

export default defineConfig({
plugins: [react()],
+ server: {
+ host: true
+ }
})

The vite dev server runs on port 5173 rather than port 3000 used by create-react-app. Moreover, the command to run the dev server is npm run dev rather than npm start. So the run command should be adjusted like so.

$ docker run -p "5173:5173" -v "$(pwd)"/src:/app/src react-app run dev

Now the dev server will be accessible at http://localhost:5173.

Notes

$ docker run -p "3000:3000" -v "$(pwd)"/src:/app/src react-app list
$ docker build -t react-app .
$ docker container prune
$ docker image prune -a
- FROM node:18-alpine
+ FROM node:18
Prabashwara Seneviratne (bash)

Written by

Prabashwara Seneviratne (bash)

Lead frontend developer