Skip to content
Back to Software Dev
Software Dev4 min read

Docker for Developers, Not Ops

dockerdevopstooling
Share

Docker content on the internet falls into two buckets: "here's what a container is" (too basic) and "here's how to orchestrate 47 microservices with Kubernetes" (too much). I need the middle ground: Docker for people who write code and want their environments to work consistently.

Here's the subset of Docker that I actually use.

dev containers: the real killer feature

Dev containers solve the "works on my machine" problem permanently. Your development environment is a Docker container defined in code. VS Code (or any editor with devcontainer support) builds and connects to it automatically.

{
  "name": "assessai-dev",
  "image": "mcr.microsoft.com/devcontainers/typescript-node:20",
  "features": {
    "ghcr.io/devcontainers/features/docker-in-docker:2": {}
  },
  "postCreateCommand": "npm install",
  "forwardPorts": [3000, 5432],
  "customizations": {
    "vscode": {
      "extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
    }
  }
}

New developer joins the project? They open the repo, VS Code builds the container, and they have a working environment with the right Node version, extensions, and dependencies. Zero setup docs. Zero "follow these 23 steps" guides.

I use this for every project now. Even solo projects. Future-me opening the repo six months later is effectively a new developer.

multi-stage builds: small images that build fast

A naive Dockerfile for a Next.js app might install everything — dev dependencies, build tools, test frameworks — in one image. You end up with a 1.2GB image where the actual app is 50MB.

Multi-stage builds fix this:

# Stage 1: Install dependencies
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
 
# Stage 2: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
 
# Stage 3: Production image
FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
 
USER node
EXPOSE 3000
CMD ["npm", "start"]

Each FROM starts a new stage. Only the final stage becomes the image. Dev dependencies, source code, build artifacts — all left behind. The production image has only what's needed to run.

The size difference matters. Smaller images deploy faster, pull faster, and have less attack surface.

docker compose for local services

Running Postgres, Redis, and your app locally? Don't install them on your machine. Use Compose:

services:
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_PASSWORD: localdev
      POSTGRES_DB: assessai
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
 
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
 
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://postgres:localdev@db:5432/assessai
      REDIS_URL: redis://redis:6379
    depends_on:
      - db
      - redis
 
volumes:
  pgdata:

docker compose up starts everything. docker compose down tears it down. Your machine stays clean. No Postgres running in the background eating RAM when you're not working on this project.

The volume mount (pgdata) persists database data between restarts. Without it, you'd lose your dev data every time you stop the containers.

the .dockerignore file nobody writes

Just like .gitignore prevents files from being tracked, .dockerignore prevents files from being copied into the build context. Without it, Docker sends your entire project directory — including node_modules, .git, .env, and test fixtures — to the Docker daemon before building.

node_modules
.git
.env*
.next
coverage
*.md
tests
e2e

I've seen Docker builds go from 45 seconds to 8 seconds just by adding a proper .dockerignore. The build context transfer was the bottleneck.

skip kubernetes

If you're a solo dev or a small team, you don't need Kubernetes. Vercel, Railway, Fly.io, or a single VPS with Docker Compose will handle your scale for a long time. Kubernetes is for operating hundreds of services with a dedicated platform team.

The Docker knowledge that matters for developers: dev containers, multi-stage builds, Compose for local services, and good .dockerignore hygiene. That covers 95% of what you'll actually need.


Share

More in Software Dev