5.3 · Docker for Node.js

Level 5 · Pro level & deployment

5.3Docker for Node.js

Goal: containerise your Node application with Docker (Dockerfile, images, containers) and orchestrate the stack with Compose — reproducibility, portability and easy deployment.
Estimated time: 11 min · self-paced reading · If you only have 5 min: read “The essentials in 30s” + the diagram.

The essentials in 30 seconds

  • The end of “it works on my machine”: the container ships the app with its environment and runs identically everywhere.
  • Image → container: the Dockerfile describes the recipe, docker build freezes the image, docker run launches the container.
  • Compose for the stack: app + database + cache described in one file and launched together — onboarding in one command.

Running case — Salim containerises in Algiers

Salim's API runs perfectly on his machine in Algiers — but crashes on his colleague's (different Node version, missing variable). He writes a Dockerfile: base Node image, dependencies installed in the image, start command. Then a Compose file with the database: a single launch brings up the whole stack. Continuation of cases 5.1-5.2 — Salim makes his app reproducible everywhere.

Continuation of cases 5.1-5.2 — Salim moves from “it works on my machine” to “the same everywhere”.

1. Containerising: image and container

Docker solves “it works on my machine” by packaging the application with its whole environment (Node version, dependencies, configuration) in an isolated, portable container that runs identically everywhere: workstation, colleague, server, cloud. Concepts: the image (frozen model of the app + environment, defined by a Dockerfile — the recipe: base Node image, copy the code, install dependencies, start command) and the container (a running instance of an image). You build (docker build), you run (docker run). .dockerignore excludes the needless from the image (node_modules — dependencies are installed INSIDE the image). Salim no longer debates versions: the environment travels with the code.

Reflex: anything specific to your machine and missing from the image is a future crash elsewhere — the image must contain everything.

2. Docker Compose and benefits

For a realistic stack (app + database + cache), Docker Compose (docker-compose.yml) defines several containers and their relationships, launched together with one command (docker compose up). A single file describes the whole stack, reproducible identically — and onboarding becomes trivial: a new developer runs one command and gets the whole environment. Benefits: reproducibility (identical everywhere), isolation (no conflicts between apps and versions), portability (any Docker host), easy deployment (deploying = launching the container — see 5.4). Salim adds the database to Compose: his colleague starts in minutes.

Docker is a standard of modern development and a cross-cutting skill (DevOps): the basics are enough to start, advanced orchestration will come as needed.

3. The right dosage for a developer

No need to become an infrastructure expert: aim for the useful basics — writing a simple Dockerfile, building and running, orchestrating app + database with Compose, excluding the needless via .dockerignore. Master Node first (your core craft), add Docker when you work as a team, prepare a deployment, or manage several services. To avoid: including node_modules in the image, aiming for advanced orchestration before the basics, or containerising a tiny learning script with no real need. Salim keeps his Dockerfile readable: six understood instructions beat a copied recipe.

The right profile: a developer who knows the basics of operations — autonomous, able not only to code but to deliver.

Common misinterpretation: “Docker is just for deployment — and I'll copy node_modules into the image to go fast.” Double mistake. Docker is useful from development onwards (identical team environment, instant onboarding), not only in production. And copying node_modules freezes binaries compiled for your machine into the image: dependencies must be installed INSIDE the image (RUN npm install), with a .dockerignore excluding them from the context.
From image to container Runs identically everywhere Dockerfile Recipe: Node +code + dependenciesdocker build Builds theIMAGE (frozen model)docker run Launches aCONTAINER (instance)Compose App + database +cache together
Runs identically everywhere
Text version of the diagram (SEO / screen readers / translation): 1) Dockerfile: Salim writes the recipe (Node image, copied code, dependencies installed in the image, start command) with a .dockerignore. 2) Build: the image freezes the app and its environment. 3) Run: the container runs identically on any machine. 4) Compose: app + database launched together with one command. Lesson: the environment travels with the code — no more “it works on my machine”.

Did you know?

“It works on my machine” has an antipattern name: environment drift. Docker eliminates it by making the environment travel with the code.
The container is the machine that travels.

Same image, same behaviour — everywhere.

🔎 Concrete example — Salim's Dockerfile

The image recipe, readable in six lines.

FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["node", "app.js"]
# .dockerignore : node_modules
# docker compose up → app + database together

Reading: each instruction has a role — base, dependencies, code, start.

Lesson: an understood Dockerfile beats a copied recipe.

Section vocabulary

Docker
Tool that packages the app with its environment in a portable container.

Simple example: Salim's API runs the same in Algiers and on his colleague's machine.

What it is not: a simple Node installer on each machine.

Reflex: does my app still depend on my machine?

Image
Frozen model of the app + environment, built from the Dockerfile.

Simple example: Salim builds a versioned image of each release.

What it is not: the running container itself.

Reflex: can I rebuild this image identically?

Dockerfile
Build recipe of the image (base, code, dependencies, start).

Simple example: Six readable instructions for Salim's API.

What it is not: a script that installs Node by hand on a server.

Reflex: is each instruction understood, not copied?

Container
A running instance of an image, isolated and portable.

Simple example: Salim launches an identical container in dev and in staging.

What it is not: the frozen image itself.

Reflex: do dev and prod launch the same image?

Docker Compose
File describing several containers launched together.

Simple example: Salim's app + database started with a single command.

What it is not: advanced Kubernetes-style orchestration.

Reflex: does a new dev start with one command?

In practice — Containerise a Node application

  1. Write a Dockerfile: start from a Node image, copy the code, install dependencies (npm install), define the start command. Add a .dockerignore (node_modules…).
  2. Build the image (`docker build`) and launch a container (`docker run`); check that the application runs in the container.
  3. Orchestrate with Docker Compose: a docker-compose.yml defining the Node app AND its database, launched together (`docker compose up`).
  4. Enjoy the benefits: reproducibility (identical everywhere), isolation, and onboarding (one `docker compose up` is enough for the whole environment).
You containerise your Node application with Docker (Dockerfile, images, containers) and orchestrate the stack with Compose — reproducibility, portability and easy deployment.

Ready-to-say script — proposing Docker to the team

“Our API works on my machine but nowhere else: it is an environment problem, not a code problem. I suggest a simple Dockerfile — six instructions — plus a Compose with the database. Everyone will run the same image, and a newcomer will start with one command. We keep it readable and skip advanced orchestration for now.”

To say in a team meeting to get containerisation adopted without aiming for DevOps expertise.

Copy-paste template — generic Node Dockerfile

FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "app.js"]
# .dockerignore :
# node_modules
# npm-debug.log
# .git

Solo / small budget

Salim alone: a simple Dockerfile with no Compose is enough — the image already freezes the environment.

Small business / small team

Compose app + database: each colleague starts the full stack with no manual installation.

SME in Algiers

Salim shares the image with the team in Algiers: everyone tests the same version, no more machine gaps.

Team starting out

Pair: one writes the Dockerfile, the other re-reads it line by line; build tested on two machines before adoption.

Caution: Never put secrets (passwords, keys, tokens) in the Dockerfile or in the image: pass them via the environment at launch. A shared image keeps all its content — an embedded secret stays readable there.

✓ Best practices

  • Master Node first, then learn the Docker basics.
  • Add a .dockerignore (exclude node_modules).
  • Use Docker Compose to orchestrate app + database (fast onboarding).

✗ Common pitfalls

  • Including node_modules in the image (install it in the image via npm install).
  • Wanting to master advanced orchestration before the basics.
  • Containerising a tiny learning script with no real need.

Key takeaways

  • DOCKER packages the application WITH its environment in an isolated, portable CONTAINER that runs IDENTICALLY everywhere — the end of “it works on my machine”.
  • IMAGE (frozen model, defined by a DOCKERFILE) → CONTAINER (instance). `docker build` / `docker run`. .dockerignore excludes node_modules.
  • DOCKER COMPOSE defines SEVERAL containers (app + database + cache) launched together (`docker compose up`) — describes the whole stack, reproducible.
  • Benefits: REPRODUCIBILITY, isolation, portability, easy deployment, fast onboarding. Modern standard (cross-cutting DevOps).

48h challenge — apply tomorrow

Write your app's Dockerfile (template above) and run it in a container: does it respond the same as on your machine?

Section exit checklist
  • I can explain image vs container in one sentence.
  • My Dockerfile builds an image that runs.
  • I know why node_modules is not in it.
Self-rating 1-5: is my image rebuildable identically?would a colleague start my stack with one command?

Frequently asked questions

What does Docker concretely bring, and is it necessary for a Node developer?

Docker mainly brings reproducibility: the end of “it works on my machine” (the container ships everything, so it runs identically everywhere). Also: isolation (several apps/versions with no conflicts), portability (any Docker host), easy deployment (deploying = launching the container), fast onboarding (one docker compose up brings up the whole stack). For learning Node or small solo projects, not strictly. For professional development, in a team or with deployment, it has become almost unavoidable — and cross-cutting. Master Node first, then the Docker basics.

Docker, deployment, CI/CD... must I become a DevOps expert on top of being a developer?

No, not an expert — but knowing the basics helps enormously: autonomy (putting your work into production), employability (job ads asking for Docker/deployment/CI-CD), better collaboration (apps that are easy to deploy), full picture of the cycle. Aim for the basics: containerising and Compose (not advanced orchestration), deploying on a simple platform, a simple CI/CD pipeline, secrets and config in environment variables, notions of logs/monitoring/HTTPS. The right profile: a developer who knows the basics of operations — able not only to code but to deliver.

Check your understanding

What problem does Docker mainly solve?

Additional resources (optional, to go further)

Level 5 examFresh, harder questions to test what you've learned