Web Development · Docker for Full-Stack
Why Every Full Stack Developer Should Learn Docker in 2026
Quick summary — why full stack developers should learn Docker
Every full stack developer should learn Docker in 2026 because it makes an app and its dependencies run the same everywhere. With one Dockerfile and one compose file you can start your API and a PostgreSQL database with a single command, onboard teammates in minutes, and ship the exact image you tested. It is now a common expectation in full-stack job descriptions.
In this guide you will learn:
- Docker in plain words — images, containers, volumes and networks.
- A working Dockerfile — for a Node.js API, with good habits.
- Compose with PostgreSQL — the full local stack in one file.
- Templates — dockerignore, commands cheat sheet and checklist.
- Interview questions — Docker questions full-stack roles ask.
SECTION 01Docker explained for full stack developers
Docker packages an application together with everything it needs to run — the runtime (such as Node.js or Python), system libraries, dependencies and start command — into an image. When you run an image, you get a container: an isolated process that behaves the same on Windows, macOS or a Linux server. For a full-stack developer, that ends the classic problem where the app works on one laptop and fails on another because of a different Node version or a missing database.
Four ideas cover most daily work. An image is the packaged template, built from a Dockerfile. A container is a running copy of it. A volume keeps data, such as database files, after a container is removed. A network lets containers talk to each other by name, so your API can reach the database at the hostname db.
| Term | Simple meaning | Full-stack example | Command to see it |
|---|---|---|---|
| Image | Read-only package of app and runtime | my-api:1.0 built from your repo | docker images |
| Container | A running instance of an image | Your API listening on port 3000 | docker ps |
| Volume | Storage that outlives containers | PostgreSQL data folder | docker volume ls |
| Network | Private link between containers | API reaches database as db:5432 | docker network ls |
# Check Docker is installed
docker --version
# Run a throwaway Node.js container and print its version
docker run --rm node:20-alpine node --version
# Run PostgreSQL locally without installing it
docker run -d --name pg-test \
-e POSTGRES_PASSWORD=devpass \
-p 5432:5432 \
postgres:16
# Connect with psql inside the container
docker exec -it pg-test psql -U postgres
# What is running?
docker ps
# Logs from a container (follow with -f)
docker logs -f pg-test
# Stop and remove it
docker stop pg-test
docker rm pg-test
# See disk usage and remove unused data
docker system df
docker system prune # asks before deleting
SECTION 02Writing a working Dockerfile for a Node.js API
A good Dockerfile for a web API follows a simple order: start from an official base image, set a working directory, copy the dependency files first, install dependencies, then copy the rest of the code. Because Docker caches each step as a layer, copying package.json before the source code means dependencies are only reinstalled when they change, which keeps rebuilds fast.
For production images, add a few habits: use a small base such as node:20-alpine or a slim variant, install only production dependencies with npm ci --omit=dev, run as the non-root node user that the official image already provides, and keep secrets out of the image. Use a .dockerignore file so node_modules and .env are never copied in.
| Instruction | What it does | Good practice | Common mistake |
|---|---|---|---|
| FROM | Chooses the base image | Pin a version like node:20-alpine | Using latest and getting surprises |
| COPY package*.json | Copies dependency manifests | Copy before source for caching | Copying everything first |
| RUN npm ci | Installs exact locked versions | Add --omit=dev for production | Using npm install without a lockfile |
| USER / CMD | Sets user and start command | Run as node, exec form CMD | Running as root, shell form CMD |
# Dockerfile — Node.js API (Express + PostgreSQL)
FROM node:20-alpine
WORKDIR /app
# 1. Dependencies first (cached unless they change)
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
# 2. Application code
COPY . .
ENV NODE_ENV=production
EXPOSE 3000
# 3. Do not run as root
USER node
CMD ["node", "server.js"]
# Build and run:
# docker build -t my-api:1.0 .
# docker run --rm -p 3000:3000 my-api:1.0
// server.js — needs: npm install express pg
const express = require("express");
const { Pool } = require("pg");
const app = express();
// DATABASE_URL comes from the environment (set in compose)
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
app.get("/health", (req, res) => res.json({ status: "ok" }));
app.get("/db-time", async (req, res) => {
try {
const result = await pool.query("SELECT NOW() AS now");
res.json(result.rows[0]);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`API listening on ${port}`));
SECTION 03Docker Compose: running the app and PostgreSQL together
Real full-stack apps need more than one container: the API, a database, perhaps a cache. Docker Compose describes all of them in a single compose.yaml file, so docker compose up starts the whole stack and docker compose down stops it. Compose also creates a shared network, which is why the API can connect to PostgreSQL using the service name db as the hostname.
Two details save beginners hours. First, the database takes a few seconds to accept connections, so add a healthcheck using pg_isready and make the API wait with depends_on and condition: service_healthy. Second, store database files in a named volume, otherwise your data disappears when the container is removed. Note that the modern command is docker compose (with a space), not the older docker-compose.
| Compose key | Purpose | Example value | Why it matters |
|---|---|---|---|
| build | Build the image from your Dockerfile | build: . | Uses your current code |
| environment | Set variables for the container | DATABASE_URL=postgres://... | Keeps config out of code |
| depends_on + healthcheck | Start order and readiness | condition: service_healthy | Avoids connection errors at start |
| volumes | Persist data | pgdata:/var/lib/postgresql/data | Database survives restarts |
# compose.yaml — API + PostgreSQL
services:
api:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://app:apppass@db:5432/appdb
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: apppass
POSTGRES_DB: appdb
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
interval: 5s
timeout: 3s
retries: 10
volumes:
pgdata:
# Build images and start everything in the background
docker compose up -d --build
# Check status and health
docker compose ps
# Test the API and the database connection
curl http://localhost:3000/health
curl http://localhost:3000/db-time
# Follow API logs
docker compose logs -f api
# Open psql in the database container
docker compose exec db psql -U app -d appdb
# Stop (data kept in the pgdata volume)
docker compose down
# Stop AND delete the database volume
docker compose down -v
SECTION 04Templates: dockerignore, cheat sheet, review checklist
Copy these into every new full-stack project so Docker stays fast, small and safe from the first commit.
# .dockerignore — keep the build context small and safe
node_modules
npm-debug.log
.git
.gitignore
.env
.env.*
coverage
dist
.vscode
.idea
Dockerfile
compose.yaml
README.md
# Without this file, a local node_modules (built for
# your OS) and your .env secrets can end up in the image.
DOCKER CHEAT SHEET FOR FULL-STACK WORK
docker build -t app:dev . # build image
docker run --rm -p 3000:3000 app:dev # run it
docker ps / docker ps -a # running / all
docker logs -f <container> # logs
docker exec -it <container> sh # shell inside
docker compose up -d --build # whole stack
docker compose logs -f api # one service
docker compose exec db psql -U app # database shell
docker compose down [-v] # stop [+ data]
docker image prune # clean old images
DOCKERFILE REVIEW CHECKLIST
[ ] Base image version pinned (no :latest)
[ ] Small base (alpine or slim) where it works
[ ] Lockfile copied and npm ci used
[ ] Dependencies copied before source (layer cache)
[ ] .dockerignore excludes node_modules and .env
[ ] No secrets in ENV lines or copied files
[ ] Runs as non-root user
[ ] CMD in exec form ["node", "server.js"]
[ ] Healthcheck or /health endpoint available
[ ] Image builds cleanly in CI
SECTION 05Tips for full stack developers learning Docker
Focus on what helps your daily work first; orchestration can wait:
- Dockerise your own project — take a project you already built and add a Dockerfile and compose file; it teaches more than tutorials.
- Read the build output — notice which steps say CACHED and reorder your Dockerfile to keep slow steps cached.
- Use service names, not localhost — inside Compose, the API reaches the database at db, not localhost.
- Keep images small — smaller images build, push and start faster; check sizes with docker images.
- Learn logs and exec early — docker logs and docker exec solve most 'why is it not working' moments.
SECTION 06Interview Q&A — Docker for full-stack roles
Q1What is the difference between a Docker image and a container?
An image is a read-only template that contains the application, its runtime and dependencies. A container is a running instance of that image with its own writable layer. You can start many containers from one image, and removing a container does not remove the image.
Q2Why do you copy package.json before the rest of the code in a Dockerfile?
Docker caches each instruction as a layer. If dependency files are copied and installed first, that layer is reused when only source code changes, so rebuilds skip npm install and finish much faster.
Q3How does an API container connect to a database container in Compose?
Compose puts services on a shared network where each service name works as a hostname. The API uses a connection string like postgres://user:pass@db:5432/appdb, where db is the database service name.
Q4How do you keep database data when containers are recreated?
Mount a named volume at the database's data directory, for PostgreSQL /var/lib/postgresql/data. The volume lives outside the container, so data survives docker compose down unless you add the -v flag.
Q5What is the difference between Docker and a virtual machine?
A virtual machine runs a full guest operating system on virtualised hardware. Containers share the host's kernel and isolate processes, so they start faster and use fewer resources, though they offer less isolation than a VM.
SECTION 07Test yourself — Docker for full stack developers
Five questions. No sign-up.
0 / 5Pick an answer to see why it is right or wrong.
SECTION 08Frequently asked questions
Do full stack developers need to know Docker?
It is increasingly expected. Many teams use Docker for local setup, testing and deployment, so knowing how to write a Dockerfile, run Compose and read container logs helps you contribute from day one and makes your portfolio easier to run.
Should I learn Docker or Kubernetes first as a web developer?
Learn Docker first. Kubernetes runs and manages containers, so it assumes you already understand images, containers, ports, volumes and environment variables. Most full-stack developers use Docker daily and touch Kubernetes far less.
Can I use Docker on Windows for web development?
Yes. Docker Desktop runs on Windows using WSL 2. Keeping your project files inside the WSL file system usually gives better performance for Node.js and Python projects than working from a Windows drive.
What is the difference between docker-compose and docker compose?
docker-compose is the older standalone tool. docker compose, with a space, is the current Compose plugin built into the Docker CLI. Most commands are the same, and new projects should use docker compose.
Is Docker useful for frontend developers using React?
Yes, mostly for consistency and deployment. You can build a React app in one stage and serve the static files with a web server such as Nginx in a smaller final image, and run the frontend alongside the API in Compose.
SECTION 09Related reads
Classroom & online · Noida
Build and ship full-stack projects with confidence
Our Python Training Course covers Python programming, web frameworks, databases and project work you can package and deploy with modern tools.
Talk to a counsellor for current fees- Python & web frameworks
- SQL & databases
- Portfolio projects
- Weekday & weekend batches