DEV Community

Cover image for How to Deploy a Multi-Container React.js and Node.js Application With Docker Compose
Bravin Wasike
Bravin Wasike

Posted on • Originally published at sweetcode.io

How to Deploy a Multi-Container React.js and Node.js Application With Docker Compose

Docker Compose is a powerful Docker tool for developing and running multi-container Dockerized applications. Docker is an open-source platform for developing and running applications in an isolated environment known as a container. A container is a standalone executable package that contains the libraries, source code, and dependencies needed to run an application.

With Docker Compose, you create a docker-compose.yml file to run all the containers in your project as a single application. The file will contain all the container configurations such as volumes, container names, and port mappings. It also specifies the Dockerfiles for building the Docker images.

In this tutorial, we will create a backend Express server using Node.js. We will then create a front-end application using React.js and connect it to the backend server.

We will then use Docker Compose to deploy the two applications. We will also access them on the web browser. Let's start working on our applications!

Prerequisites

This tutorial assumes you are familiar with the following:

To implement this tutorial, you will need the following already installed on your computer:

Creating the Backend Express Server using Node.js

To create the Express server using Node.js, follow the steps illustrated below:

Step 1: Create a working directory named docker-compose-app and open it with VS Code.
In the working directory, create a new directory/folder named node and cd into the node directory. This directory will contain the libraries, source code, and dependencies needed to create the application.

Step 2: Initialize the application using the following code:

npm init --y
Enter fullscreen mode Exit fullscreen mode

The command will initialize the application and generate the package.json file. The next step is to install all the dependencies for the application as follows:

npm i -g nodemon
npm i express
Enter fullscreen mode Exit fullscreen mode

After running the command in your terminal, it will install express and nodemon. We will use the installed express package to create the server.

We will use nodemon to watch and monitor the backend files. Nodemon will detect changes in the backend files and automatically restart the server. It will prevent us from restarting the backend server manually after making changes to the application.

Step 3: Next, open the package.json file and the following npm script for nodemon to start working:

"dev": "nodemon -L app.js"
Enter fullscreen mode Exit fullscreen mode

Step 4: In the node directory, create a new file named server.js. This file will have the logic for creating our backend server.

Step 5: Copy and paste the following code snippet in the server.js file:

const express = require('express')
const cors = require('cors')

const app = express()

app.use(cors())

app.get('/', (req, res) => {
  res.json([
    {
      "id":"1",
      "title":"Album Review: When we all Fall asleep where do we go?"
    },
    {
      "id":"2",
      "title":"Book Review: How can we escape this labyrinth of suffering?"
    },
    {
      "id":"3",
      "title":"Documentary Review: How can we escape the rat race?"
    }
  ])
})

app.listen(4000, () => {
  console.log('connected on port 4000')
})
Enter fullscreen mode Exit fullscreen mode

The code snippet above will create a get route. The frontend application will get the review titles from this route.

Running the Backend Express Server

To run the Backend Express Server application, run the following npm command in your terminal:

npm run dev
Enter fullscreen mode Exit fullscreen mode

The npm command will start and run our server on http://localhost:4000/as shown in the image below:

Image description

The image shows the backend is running and displaying the reviews. Let's start working on our frontend React.js application.

Creating the frontend React.js application

To create the frontend React.js application, follow the steps illustrated below:

Step 1: In the docker-compose-app working directory, run the following npx command to create a boilerplate for a React.js application

npx create-react-app react
Enter fullscreen mode Exit fullscreen mode

The npx command above will create a new directory named react in the docker-compose-app working directory. Now, cd into the react directory.

Step 2: Navigate inside the react directory, and open the src directory.

Step 3: While in the src directory, open the App.js file and add the following code snippet:

import { useEffect, useState } from 'react'
import './App.css';

function App() {
  const [reviews, setReviews] = useState([])
  useEffect(() => {
    fetch('http://localhost:4000/')
      .then(res => res.json())
      .then(data => setReviews(data))
  }, [])

  return (
    <div className="App">
      <header className="App-header">
        <h1>all Reviews</h1>
        {reviews && reviews.map(blog => (
          <div key={blog.id}>{blog.title}</div>
        ))}
      </header>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

The added code snippet will create a frontend react application. It will fetch the review titles from this backend get route. Our backend application is running on http://localhost:4000/. The next step is to run the frontend React.js application as follows:

Running the frontend React.js application

To run the frontend React.js application, execute the following command in your terminal:

npm start
Enter fullscreen mode Exit fullscreen mode

The npm command will start and run the frontend React.js application on http://localhost:3000/as shown in the image below:

Image description

The image shows the frontend React.js application running and fetching the review titles from the backend. Let's create the Dockerfiles for the two applications. Docker Compose will use the Dockerfiles to build and run the containers.

Create the Dockerfile for the Backend Express Server

The Dockerfile will contain all the commands for building the Docker image for the backend server application. While in the node directory/folder, create a new file named Dockerfile. In the created Dockerfile add the following commands to create a Docker image.

# It uses node:18-alpine as the base image for the Node.js application
FROM node:18-alpine

# It installs the nodemon package globally for monitoring and watching the backend Express server
RUN npm install -g nodemon

# Creating the working directory named `app`
WORKDIR /app

# Copying all the tools and dependencies in the package.json file to the working directory `app`
COPY package.json .

#Installing all the tools and dependencies in the container
RUN npm install

#Copying all the application source code and files to the working directory `app`
COPY . .

#Exposing the container to run on this port 4000
EXPOSE 4000

#Command to start the Docker container for the backed server application
CMD ["npm", "run", "dev"]
Enter fullscreen mode Exit fullscreen mode

The next step is to create a Dockerfile for the frontend React.js application.

Create the Dockerfile for the frontend React.js application

In the react directory/folder, create a new file named Dockerfile. In the created Dockerfile add the following commands to create a Docker image.

# It uses node:18-alpine as the base image for the frontend React.js application
FROM node:18-alpine

# Creating the working directory named `app`
WORKDIR /app

# Copying all the tools and dependencies in the package.json file to the working directory `app`
COPY package.json .

#Installing all the tools and dependencies in the container
RUN npm install

#Copying all the application source code and files to the working directory `app`
COPY . .

#Exposing the container to run on this port 3000
EXPOSE 3000

#Command to start the Docker container for the frontend React.js application
CMD ["npm", "start"]
Enter fullscreen mode Exit fullscreen mode

Now that we have both Dockerfiles, the next step is to create a docker-compose.yml file which contains all the containers' configurations.

Create a docker-compose.yml file

This file will enable us to run and deploy the two containers using Docker Compose. We will add the containers as a service.

The docker-compose.yml file will have two services. Using the created file, we will spin up the two containers. It will run them as a single application.

To create the two Docker Compose services, follow the steps below:

Step 1: In the docker-compose-app working directory, create a new file docker-compose.yml file.

Step 2: Next, add the first service named node using the following code snippet:

# Version of Docker-compose
version: '3.9'
services:
  # Add the node-js service
  node:
  # Location to the node.js dockerfile
    build: 
      context: ./node
        # Name of the dockerfile
      dockerfile: Dockerfile
    container_name: node-container
    ports:
       # Host port:Container port
      - '4000:4000'
    volumes:
      # Bind-mounts configuration
      - ./node:/app
      # Ignoring any changes made in the "node_modules" folder
      - ./app/node_modules
Enter fullscreen mode Exit fullscreen mode

The code above will create a service named node. It also shows the location of the Node.js Dockerfile.

It shows the container name as node-container and port mapping. The node-container will run on port 4000.

We also add volume for this service. This volume will map the local project folder to the working directory in the container. Any changes made in the local project folder will be updated automatically in the container. It saves time rebuilding the whole container from scratch when change the files in the local project folder.

Step 3: Next, let's add the service named react for the React.js application container.

After the node service, add the following code snippet:

 react:
  # Location to the react.js dockerfile
    build: 
      context: ./react
        # Name of the dockerfile
      dockerfile: Dockerfile
    container_name: react-container
    ports:
     # Host port:Container port
      - '3000:3000'
    stdin_open: true
Enter fullscreen mode Exit fullscreen mode

The code above will create a service named react. It also shows the location of the React.js Dockerfile.

It shows the container name as react-container and port mapping. The react-container will run on port 3000.

If you follow the steps above correctly, the final docker-compose.yml will be as shown below:

# Version of Docker-compose
version: '3.9'
services:
  # Add the node-js service
  node:
  # Location to the node.js dockerfile
    build: 
      context: ./node
        # Name of the dockerfile
      dockerfile: Dockerfile
    container_name: node-container
    ports:
       # Host port:Container port
      - '4000:4000'
    volumes:
      # Bind-mounts configuration
      - ./node:/app
      # Ignoring any changes made in "node_modules" folder
      - ./app/node_modules
  react:
  # Location to the react.js dockerfile
    build: 
      context: ./react
        # Name of the dockerfile
      dockerfile: Dockerfile
    container_name: react-container
    ports:
     # Host port:Container port
      - '3000:3000'
    stdin_open: true
Enter fullscreen mode Exit fullscreen mode

Now that we have added all our services to the file, the next step is to build and run the two containers.

Running the two Containers using Docker Compose

To build and run the two Containers using Docker Compose, execute the following command in your terminal:

docker-compose up --build
Enter fullscreen mode Exit fullscreen mode

The command will run the two containers and display the following output in your terminal:

Image description

The output shows both the node-container and react-container are running. We can access the node-container on http://localhost:4000/ and react-container on http://localhost:3000/. The images below show the deployed containers running in the web browser:

  • node-container
    Image description

  • react-container
    Image description

Conclusion

In this tutorial, you have learned how to deploy a multi-container React.js and Node.js Application using Docker Compose. We created a backend Express server using Node.js. We then created a front-end application using React.js. After completing these steps, we created Dockerfiles for these two applications. We also created a docker-compose.yml file.

We used the docker-compose.yml to build and run the two application containers. We successfully deployed the Docker containers using Docker Compose. We accessed them on the web browser. You can download the complete source code for this tutorial here. Happy Deployment!

Top comments (10)

Collapse
 
stevereid profile image
Steve Reid

A good article.
I feel that it would've been a great article if it had also encompassed use environment variables within this setup as it can be a bit of a gotcha.

Collapse
 
bravinsimiyu profile image
Bravin Wasike

Yeah- that's a great idea.

Collapse
 
monfernape profile image
Usman Khalil

This is an amazing write-up. Very easy to consume

Collapse
 
bravinsimiyu profile image
Bravin Wasike

Thanks for reading.

Collapse
 
onlinemsr profile image
Raja MSR

Thank you for this informative and helpful blog post. I learned a lot from your clear and detailed explanation of how to deploy a multi-container ReactJS and NodeJS application with Docker Compose.

Collapse
 
bravinsimiyu profile image
Bravin Wasike

Thanks for reading.

Collapse
 
lyaaaa profile image
lyaaaa

Why not use nginx as a proxy when building React.js Docker?

Collapse
 
davboy profile image
Daithi O’Baoill

Nice post, thank you.

Collapse
 
caritop11 profile image
caritop11

this is interesting

Collapse
 
bravinsimiyu profile image
Bravin Wasike

Thanks for reading.