Skip to main content

Building Docker Images for React Applications

Docker can also be used to containerize frontend applications like React. This process allows you to easily share, deploy, and run your React applications on any platform.

Let’s explore how to:

  • Create a Dockerfile for a React app
  • Build custom Docker images
  • Run the image with or without Docker Compose

Example 1: Simple React Application

We will start by creating a basic React application using create-react-app, and then containerize it using Docker.

Step 1: Initialize a React App

If you haven't already, create a React app by running the following command:

npx create-react-app my-react-app

This creates a React app in the my-react-app directory.

Step 2: Writing the Dockerfile

Create a Dockerfile inside the my-react-app directory.

# Use an official Node runtime as a parent image
FROM node:20-alpine

# Set the working directory inside the container
WORKDIR /app

# Copy the package.json and package-lock.json to the container
COPY package*.json ./

# Install the dependencies
RUN npm install

# Copy the rest of the React app source code into the container
COPY . .

# Build the app for production
RUN npm run build

# Use Nginx to serve the built React app
FROM nginx:alpine
COPY --from=0 /app/build /usr/share/nginx/html

# Expose port 80
EXPOSE 80

# Start Nginx server
CMD ["nginx", "-g", "daemon off;"]

Explanation:

  1. FROM node:16-alpine: Use a lightweight Node.js image based on Alpine Linux for building the app.
  2. WORKDIR /app: Set /app as the working directory inside the container.
  3. COPY package*.json ./: Copy package.json and package-lock.json to install dependencies first.
  4. RUN npm install: Install the app dependencies (React and other libraries).
  5. COPY . .: Copy the remaining app files into the /app directory.
  6. RUN npm run build: Build the React app for production.
  7. FROM nginx:alpine: Switch to a minimal Nginx image to serve the built app. This results in a smaller final image.
  8. COPY --from=0 /app/build /usr/share/nginx/html: Copy the build folder (the output of npm run build) from the first stage into the Nginx web server’s html directory.
  9. EXPOSE 80: Expose port 80 for HTTP traffic.
  10. CMD ["nginx", "-g", "daemon off;"]: Run Nginx to serve the app.

Two Ways to Run Your React Docker Image

You can run your Docker image using either Docker Compose or directly using Docker commands.

1. Running with Docker Compose

Here’s a docker-compose.yml file for running the React app using Docker Compose:

version: '3'
services:
react-app:
build: .
ports:
- "3000:80"
volumes:
- .:/app
stdin_open: true
tty: true

Explanation:

  • build: .: Tells Docker Compose to build the image from the current directory where the Dockerfile resides.
  • ports: "3000:80": Maps port 3000 on the host to port 80 in the container (Nginx).
  • volumes: .:/app: Mounts the current directory into the container so you can make live changes to the code.
  • stdin_open and tty: These flags allow you to attach a terminal to the container if needed.

Run the app using Docker Compose with:

docker compose up

This command will:

  • Build the Docker image.
  • Start the container.
  • Map port 3000 on your machine to port 80 in the container.

Access the React app at http://localhost:3000.

2. Running Without Docker Compose

You can also run the app directly using Docker commands.

First, build the Docker image:

docker build -t my-react-app .

Then, run the container:

docker run -p 3000:80 my-react-app

This command maps port 3000 on your machine to port 80 in the container, allowing you to access the React app at http://localhost:3000.


Example 2: Optimizing the React Build for Production

React apps often need optimization when built for production. Docker’s multi-stage builds can help create lightweight images, ensuring the app is fast and efficient.

Here’s how we can optimize the Dockerfile:

# Stage 1: Build the React app
FROM node:16-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# Stage 2: Serve the built app using Nginx
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Explanation:

  • FROM node:16-alpine AS builder: Use a multi-stage build where the first stage (builder) is responsible for building the app.
  • COPY --from=builder: In the second stage, copy only the built files from the builder stage to the Nginx image, reducing the final image size.

Example 3: Using Environment Variables in Docker for React

You can pass environment variables to a React app at build time. Here's how:

  1. In the React app, create a .env file to store environment variables:
REACT_APP_API_URL=https://api.example.com
  1. Update the Dockerfile to copy this .env file:
# Stage 1: Build the React app
FROM node:16-alpine AS builder

WORKDIR /app
COPY package*.json ./
COPY .env /app/.env # Add this line
RUN npm install
COPY . .
RUN npm run build

# Stage 2: Serve the built app using Nginx
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

This is especially useful because in most cases you will be having a seperate backend for your react application and it is better to pass the backend url as an environment variable than hardcode it.


Summary

  • Dockerfiles for React apps follow a similar pattern to backend apps, but they include npm commands for building the app and a web server like Nginx for serving the static build files.
  • You can run the Dockerized React app with or without Docker Compose.

This section now covers React applications with examples of multi-stage builds and environment variables, giving both Compose and non-Compose methods to run the app.