Docker and JavaScript: Containerizing Applications from A to Z

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Docker and JavaScript: Containerizing Node.js Applications — A Complete Guide



In modern web development, containerization has become not just a trend, but a necessity. Docker allows you to package a JavaScript application together with all its dependencies, configurations, and runtime environment into an isolated container that will work identically on any system — from a developer's laptop to a production server. In this article, we will walk through the process of containerizing Node.js applications from scratch, covering best practices and typical use cases.



Docker Basics for JavaScript Developers



Before diving into the details, let's understand the key Docker concepts as they apply to the JavaScript ecosystem.



  • Image — an immutable template containing code, the Node.js runtime, dependencies (node_modules), and configurations. Images are stored in a registry (e.g., Docker Hub).
  • Container — a running instance of an image. Each container is isolated from others and from the host system.
  • Dockerfile — instructions for building an image. For Node.js applications, this is the primary file we will create.
  • docker-compose — a tool for defining and running multi-container applications (e.g., Node.js + MongoDB + Redis).


Creating a Dockerfile for a Node.js Application



Let's start with a simple Express application. Create a file named Dockerfile in the project root:



# Base Node.js 18 image (Alpine — lightweight version)FROM node:18-alpine

# Create a working directory inside the containerWORKDIR /usr/src/app

# Copy package.json and package-lock.json (if present)COPY package*.json ./

# Install production dependenciesRUN npm ci --only=production

# Copy the application source codeCOPY . .

# Expose the port the app will listen onEXPOSE 3000

# Command to run the applicationCMD ["node", "src/index.js"]


Important nuances for JavaScript projects:

  • The order of instructions matters. Copying package.json before the code allows Docker to cache the layer with dependency installation. If you only change the code, dependencies are not reinstalled — this speeds up the build.
  • Use npm ci instead of npm install — it is faster and ensures dependency versions match the lock file.
  • The Alpine version of the Node.js image (~120 MB instead of ~900 MB) significantly reduces the final image size.


Working with docker-compose: Connecting Node.js to a Database



Real-world applications rarely use a single container. docker-compose.yml allows you to run Node.js, MongoDB, and, for example, Redis with a single command:



version: '3.8'services:  app:    build: .    ports:      - "3000:3000"    environment:      - NODE_ENV=production      - MONGODB_URI=mongodb://mongo:27017/myapp      - REDIS_URL=redis://redis:6379    depends_on:      - mongo      - redis    volumes:      - ./logs:/usr/src/app/logs

mongo: image: mongo:6 volumes: - mongo_data:/data/db ports: - "27017:27017"

redis: image: redis:7-alpine ports: - "6379:6379"

volumes: mongo_data:


How it works:

  • The app service is built from our Dockerfile.
  • The mongo and redis services use ready-made images from Docker Hub.
  • The environment variables MONGODB_URI and REDIS_URL are passed to the application — note that we use the service names as hostnames (Docker DNS automatically resolves them to the container IP addresses).
  • The mongo_d

Blogs

Book Recommendations