Skip to main content

Docker for Web Developers

Containerize a Node + React app with multi-stage builds and tiny production images.

Web DevelopmentIntermediate 15 min read 5 lessons
DockerDevOps

What You'll Learn

  • Write a production-grade multi-stage Dockerfile
  • Use .dockerignore to keep builds fast and images small
  • Compose a full Node + React stack with docker-compose
  • Debug running containers with exec and logs
  • Push images to Docker Hub or a private registry

Prerequisites

  • Node.js basics
  • Terminal comfort (cd, ls, mkdir)
  • Docker Desktop installed

Step-by-Step Guide

  1. Step 1

    1. Your First Dockerfile

    Create a Dockerfile at the project root. Start with FROM node:20-alpine (Alpine = tiny base image). Set WORKDIR /app. COPY package*.json ./ then RUN npm ci --only=production (not npm install — ci is deterministic). COPY . . then EXPOSE 3000 and CMD ['node', 'server.js']. Build with docker build -t myapp:latest . and run with docker run -p 3000:3000 myapp:latest.

  2. Step 2

    2. Multi-Stage Builds

    Stage 1 (builder): FROM node:20 AS builder — install all deps and run the React build. Stage 2 (runtime): FROM node:20-alpine — copy only the build output and production deps from the builder stage. COPY --from=builder /app/dist ./dist. Result: a production image with no dev tools, no source maps, no node_modules bloat. Typically reduces image size from 1.5GB to 150MB.

  3. Step 3

    3. .dockerignore

    Add .dockerignore alongside .gitignore. Include: node_modules, .git, .env, dist, *.log, .DS_Store, coverage. Without this, Docker's build context uploads your entire node_modules on every build — often 500MB+. With .dockerignore, the context is usually < 1MB. This dramatically speeds up builds and prevents secrets from leaking into images.

  4. Step 4

    4. Docker Compose for Local Dev

    Create docker-compose.yml: define a web service (your Node app), a db service (postgres:16-alpine), and an optional redis service. Mount your source with volumes: - .:/app:delegated for hot reload. Use environment variables from a .env file with env_file: .env. Run docker compose up -d to start everything. docker compose logs -f web to tail logs.

  5. Step 5

    5. Push to a Registry & Deploy

    Tag your image: docker tag myapp:latest yourusername/myapp:v1.0.0. Push: docker push yourusername/myapp:v1.0.0. On your server: docker pull yourusername/myapp:v1.0.0 && docker run -d -p 80:3000 --env-file .env yourusername/myapp:v1.0.0. Use a private registry (ECR, GCR, or GHCR) for production. Set up a GitHub Actions workflow to build and push automatically on every push to main.

Further Reading & Resources

Ready to put this into practice?

Apply for a real Web Development internship and ship production projects with mentorship.

Related Tutorials