Docker Compose MERN/MEAN Stack: Complete Reference

Type: Software Reference Confidence: 0.93 Sources: 7 Verified: 2026-02-27 Freshness: 2026-02-27

TL;DR

Constraints

Quick Reference

Service Architecture

ServiceImagePortsVolumesKey Env
MongoDBmongo:8.0None (internal only)mongo-data:/data/dbMONGO_INITDB_ROOT_USERNAME, MONGO_INITDB_ROOT_PASSWORD
Express APInode:22-slim (custom)3001:3001./server:/app (dev only)NODE_ENV, MONGODB_URI, PORT
React Frontendnode:22-slimnginx:1.27-alpineNone (proxied)./client:/app (dev only)REACT_APP_API_URL (build-time)
Angular Frontendnode:22-slimnginx:1.27-alpineNone (proxied)./client:/app (dev only)API_URL (build-time)
Nginx Proxynginx:1.27-alpine80:80, 443:443./nginx/nginx.conf:/etc/nginx/nginx.conf:roNone

Connection Strings (Internal Docker Network)

FromToConnection String
Express APIMongoDBmongodb://root:password@mongo:27017/appdb?authSource=admin
NginxExpress APIhttp://api:3001 (proxy_pass)
NginxReact/AngularServes static files from build stage
BrowserNginxhttp://localhost or https://localhost

Docker Compose V2 Commands

CommandPurpose
docker compose up --build -dBuild images and start all services
docker compose down -vStop services and remove volumes (dev reset)
docker compose logs -f apiFollow logs for the API service
docker compose exec mongo mongosh -u root -pOpen MongoDB shell
docker compose psList running services and health status
docker compose build --no-cache apiRebuild specific service without cache

Decision Tree

START: What type of deployment do you need?
├── Development (hot reload)?
│   ├── YES → Use bind mounts for source code + nodemon for API + Vite/ng serve for frontend
│   └── NO ↓
├── Production (optimized)?
│   ├── YES → Multi-stage builds + Nginx reverse proxy + no bind mounts + health checks
│   └── NO ↓
├── MERN (React)?
│   ├── YES → Multi-stage Dockerfile: node:22-slim (build) → nginx:1.27-alpine (serve)
│   └── NO ↓
├── MEAN (Angular)?
│   ├── YES → Multi-stage Dockerfile: node:22-slim (build with ng build) → nginx:1.27-alpine (serve)
│   └── NO ↓
├── Need MongoDB replica set (transactions)?
│   ├── YES → Add --replSet rs0 + keyFile + rs.initiate() init script
│   └── NO ↓
└── DEFAULT → Standard 3-service compose: mongo + api + client with Nginx

Step-by-Step Guide

1. Create project directory structure

Set up the standard MERN project layout that Docker Compose expects. [src1]

mkdir -p mern-docker/{client,server,nginx,mongo-init}
cd mern-docker
touch docker-compose.yml .env .dockerignore

Verify: ls -la → should show client/, server/, nginx/, mongo-init/, docker-compose.yml, .env

2. Configure environment variables

Create a .env file at the project root. Docker Compose automatically loads this file. [src3]

# .env -- NEVER commit this file to version control
NODE_ENV=production
MONGO_ROOT_USER=root
MONGO_ROOT_PASSWORD=changeme_strong_password_here
MONGO_DB=appdb
MONGO_PORT=27017
API_PORT=3001

Verify: docker compose config → should show interpolated environment variables

3. Write the Docker Compose file

Create the multi-service configuration with health checks and dependency ordering. [src6]

# docker-compose.yml -- Production MERN stack
services:
  mongo:
    image: mongo:8.0
    restart: unless-stopped
    environment:
      MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USER}
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD}
    volumes:
      - mongo-data:/data/db
    healthcheck:
      test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

Verify: docker compose config --services → should list: mongo, api, client, nginx

4. Create the Node.js API Dockerfile

Build a production-ready Express API image with proper security. [src3]

# server/Dockerfile
FROM node:22-slim AS base
WORKDIR /app
ENV NODE_ENV=production
RUN apt-get update && apt-get install -y --no-install-recommends dumb-init \
    && rm -rf /var/lib/apt/lists/*
COPY --chown=node:node package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --chown=node:node . .
USER node
EXPOSE 3001
CMD ["dumb-init", "node", "server.js"]

Verify: docker build -t mern-api ./server → should complete without errors

5. Create the React frontend multi-stage Dockerfile

Build React with Node, then serve with Nginx for minimal image size. [src4]

# client/Dockerfile (React/Vite)
FROM node:22-slim AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM node:22-slim AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM nginx:1.27-alpine AS production
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

Verify: docker build -t mern-client ./client → final image should be < 50MB

6. Configure Nginx as reverse proxy

Create the Nginx configuration that routes API requests and serves static files. [src5]

# nginx/nginx.conf
worker_processes auto;
events { worker_connections 1024; }
http {
    include /etc/nginx/mime.types;
    upstream api { server api:3001; }
    server {
        listen 80;
        location /api/ { proxy_pass http://api/; }
        location / {
            root /usr/share/nginx/html;
            try_files $uri $uri/ /index.html;
        }
    }
}

Verify: docker compose up nginxcurl -I http://localhost should return 200

7. Create MongoDB initialization script

Set up application database and user with least-privilege access. [src2]

// mongo-init/01-create-app-user.js
db.createUser({
  user: 'appuser',
  pwd: 'app_password_change_me',
  roles: [
    { role: 'readWrite', db: 'appdb' },
    { role: 'dbAdmin', db: 'appdb' }
  ]
});
print('MongoDB init complete: appuser created');

Verify: docker compose exec mongo mongosh -u root -p --eval "db.getUsers()" → should list appuser

8. Start the full stack

Launch all services and verify connectivity. [src7]

# Build and start all services
docker compose up --build -d

# Check all services are healthy
docker compose ps

# Test API connectivity through Nginx
curl http://localhost/api/health

Verify: docker compose ps → all services should show "healthy" or "running"

Code Examples

Complete docker-compose.yml (Production)

Full script: docker-compose-production.yml (68 lines)

services:
  mongo:
    image: mongo:8.0
    restart: unless-stopped
    environment:
      MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USER}
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD}
    volumes:
      - mongo-data:/data/db
      - ./mongo-init:/docker-entrypoint-initdb.d:ro
    healthcheck:
      test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
      interval: 10s
      timeout: 5s
      retries: 5

Complete docker-compose.dev.yml (Development)

Full script: docker-compose-dev.yml (54 lines)

services:
  mongo:
    image: mongo:8.0
    ports:
      - "27017:27017"
    environment:
      MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USER}
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD}
    volumes:
      - mongo-data:/data/db

Node.js API Dockerfile (Production)

Full script: server-dockerfile (32 lines)

FROM node:22-slim AS base
WORKDIR /app
ENV NODE_ENV=production
RUN apt-get update && apt-get install -y --no-install-recommends dumb-init \
    && rm -rf /var/lib/apt/lists/*
COPY --chown=node:node package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --chown=node:node . .
USER node
CMD ["dumb-init", "node", "server.js"]

React Multi-Stage Dockerfile

Full script: client-dockerfile-react (31 lines)

FROM node:22-slim AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM node:22-slim AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM nginx:1.27-alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80

Anti-Patterns

Wrong: Storing credentials in docker-compose.yml

# BAD -- credentials in plain text, committed to version control
services:
  mongo:
    image: mongo:8.0
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin
      MONGO_INITDB_ROOT_PASSWORD: supersecret123

Correct: Using .env file or Docker secrets

# GOOD -- credentials loaded from .env file (never committed)
services:
  mongo:
    image: mongo:8.0
    environment:
      MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USER}
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD}

Wrong: Using node:latest and running as root

# BAD -- unpinned version, running as root, using npm start
FROM node:latest
WORKDIR /app
COPY . .
RUN npm install
CMD ["npm", "start"]

Correct: Pinned version, non-root user, proper signal handling

# GOOD -- pinned LTS, dumb-init for signals, non-root user
FROM node:22-slim
WORKDIR /app
ENV NODE_ENV=production
RUN apt-get update && apt-get install -y --no-install-recommends dumb-init \
    && rm -rf /var/lib/apt/lists/*
COPY --chown=node:node package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --chown=node:node . .
USER node
CMD ["dumb-init", "node", "server.js"]

Wrong: Single-stage frontend build (bloated image)

# BAD -- 1.2GB image includes node_modules, source, build tools
FROM node:22
WORKDIR /app
COPY . .
RUN npm install && npm run build
CMD ["npx", "serve", "-s", "build"]

Correct: Multi-stage build (< 50MB image)

# GOOD -- only Nginx + static files in final image (~25MB)
FROM node:22-slim AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:1.27-alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

Wrong: depends_on without health checks

# BAD -- API starts before MongoDB is ready
services:
  api:
    depends_on:
      - mongo

Correct: depends_on with condition: service_healthy

# GOOD -- API waits for MongoDB health check to pass
services:
  api:
    depends_on:
      mongo:
        condition: service_healthy
  mongo:
    healthcheck:
      test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

Wrong: Exposing MongoDB to host in production

# BAD -- MongoDB accessible from outside Docker network
services:
  mongo:
    ports:
      - "27017:27017"

Correct: Internal-only MongoDB access

# GOOD -- MongoDB only accessible within Docker network
services:
  mongo:
    expose:
      - "27017"
    # No 'ports' directive -- only other containers can reach it

Common Pitfalls

Diagnostic Commands

# Check all service status and health
docker compose ps

# View logs for a specific service
docker compose logs -f api

# Test MongoDB connectivity from API container
docker compose exec api node -e "
  const { MongoClient } = require('mongodb');
  MongoClient.connect(process.env.MONGODB_URI)
    .then(() => console.log('MongoDB OK'))
    .catch(e => console.error('MongoDB FAIL:', e.message));
"

# Check MongoDB health directly
docker compose exec mongo mongosh --eval "db.adminCommand('ping')" -u root -p

# Check image sizes
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" | grep -E "mern|mongo|nginx"

# Check container resource usage
docker compose stats --no-stream

# Test Nginx proxy configuration
docker compose exec nginx nginx -t

# Verify no credentials in image layers
docker history mern-api --no-trunc | grep -i password

Version History & Compatibility

ComponentVersionStatusNotes
Docker ComposeV2 (docker compose)CurrentV1 (docker-compose) deprecated Jan 2024
MongoDB8.0CurrentRequires mongosh (mongo shell removed in 6.0)
MongoDB7.0LTS until 2027Last version with Debian 11 support
Node.js22 LTSCurrent (Active LTS until Oct 2027)Recommended for production
Node.js20 LTSMaintenance until Apr 2026Still widely used
Nginx1.27Current mainlineAlpine variant recommended for size
React19CurrentVite preferred over CRA (deprecated)
Angular19CurrentStandalone components default

When to Use / When Not to Use

Use WhenDon't Use WhenUse Instead
Development environment for 1-5 developersMulti-node production cluster with auto-scalingKubernetes or Docker Swarm
Single-server production deployment (< 10K RPM)High-availability MongoDB requirementMongoDB Atlas + containerized API
CI/CD integration testingServerless/edge deploymentVercel/Netlify (frontend) + managed DB
Consistent environment across dev/staging/prodNeed GPU workloads or specialized hardwareCloud-specific services (ECS, Cloud Run)
Quick prototyping and demosMicroservices with 10+ servicesKubernetes with Helm charts

Important Caveats

Related Units