Why Docker Has Become a Developer Essential

Docker solves one of the oldest problems in software: "It works on my machine." By packaging an application along with its entire runtime environment — OS libraries, dependencies, config — into a portable container, Docker ensures your app runs the same way everywhere: your laptop, a teammate's machine, a CI server, or a production cloud.

You don't need to be a DevOps engineer to benefit from Docker. This guide focuses on the developer use cases that matter most day-to-day.

Core Concepts in Plain English

Images

An image is a read-only blueprint for a container. Think of it like a class definition. Images are built from a Dockerfile and stored in registries like Docker Hub.

Containers

A container is a running instance of an image — the actual executing process, isolated from the host system. You can run many containers from the same image.

Dockerfile

A text file with instructions that tell Docker how to build your image.

# Example Dockerfile for a Node.js app
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

Volumes

Containers are ephemeral — data written inside a container disappears when it stops. Volumes are how you persist data (databases, uploaded files) outside the container lifecycle.

Essential Docker Commands

CommandWhat It Does
docker build -t myapp .Build an image from the current directory's Dockerfile
docker run -p 3000:3000 myappRun a container, mapping port 3000
docker psList running containers
docker logs <container_id>View container output/logs
docker exec -it <id> shOpen an interactive shell inside a running container
docker stop <id>Gracefully stop a container
docker system pruneRemove unused containers, images, and networks

Docker Compose: Managing Multi-Container Apps

Real applications often need multiple services — a web app, a database, a cache. Docker Compose lets you define and run them all with a single docker-compose.yml file.

version: "3.9"
services:
  web:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - db
    environment:
      DATABASE_URL: postgres://user:pass@db:5432/mydb

  db:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb

volumes:
  pgdata:

With this file, docker compose up starts both services, and docker compose down tears them down cleanly.

Developer Workflow Tips

  • Use bind mounts during development so code changes inside the container reflect immediately without rebuilding the image: -v $(pwd):/app.
  • Use multi-stage builds to keep production images small — build in one stage, copy only the output to the final image.
  • Add a .dockerignore file (like .gitignore) to exclude node_modules, .git, and other unnecessary files from the build context.
  • Tag images meaningfully: myapp:1.2.0 instead of relying solely on latest.

Common Gotchas

  • Container networking: services in the same Compose file communicate by service name, not localhost.
  • File permissions can differ between macOS/Windows hosts and Linux containers — especially relevant with volume mounts.
  • Don't bake secrets into images. Use environment variables or secret management tools instead.

Next Steps

Once you're comfortable with the basics, explore Docker Desktop's Dev Containers feature, which integrates deeply with VS Code for a fully containerized development environment. For production, look into Kubernetes or managed container services like AWS ECS, Google Cloud Run, or Railway.