react-node-docker-demo/
├── client/ # React frontend
│ ├── Dockerfile
│ ├── package.json
│ └── src/
│ └── App.js
├── server/ # Node backend (Express)
│ ├── Dockerfile
│ ├── package.json
│ └── index.js
└── docker-compose.yml
FROM node:18-alpine: start from a lightweight Node 18 image (small, fast).WORKDIR /app: this sets/appas the working directory inside our container.COPY package*.json ./: this will copypackage.jsonandpackage-lock.jsonso Docker can install all the dependencies before copying the full source.RUN npm install: this will install dependencies inside the image.COPY . .: this copies the rest of the frontend code into the image.EXPOSE 3001: this line exposes the port that our frontend server will run on.CMD ["npm", "start"]: this defines our default command to start our React development server.
- Each line will do the exact same thing as it did for frontend except it will expose port 3000 where the backend will be listening.
alpineis a lightweight version of Linux called Alpine Linux, we use it because it helps our image download and build faster (also uses less memory and disk space).
services:
backend:
build: ./server
ports:
- "3000:3000"
container_name: backend
networks:
- app-network
frontend:
build: ./client
ports:
- "3001:3001"
depends_on:
- backend
environment:
- PORT=3001
container_name: frontend
networks:
- app-network
networks:
app-network:
driver: bridgeservices: this groups the containers (backend + frontend).build: ./server/build: ./client: this tells Docker Compose where each Dockerfile is.ports: maps host:container solocalhost:3000= backend container's3000.depends_on: this ensures that the backend starts up before our frontend.networks: this creates an internal network so the frontend can callhttp://backend:3000from inside the container.
docker-compose up --build
docker compose up
ctrl + c
docker compose down