A Dockerfile should produce a repeatable image from declared inputs rather than depend on a developer machine.
Course navigationPhase 32⌄
Docker
Containerize the production API/web artifacts reproducibly with secure runtime configuration, small images, health checks, networking, and graceful shutdown.
Phase outcome and project increment
Learning outcome
Containerize the production API/web artifacts reproducibly with secure runtime configuration, small images, health checks, networking, and graceful shutdown.
Concrete deliverable
Dockerfiles and compose/dev verification that build and run TaskFlow services from clean inputs.
Principles to keep while coding
Use multi-stage builds to keep runtime images smaller and separate build-time tools from production dependencies.
Do not bake secrets into images; inject runtime configuration through the deployment environment.
Health checks and graceful shutdown help orchestrators know when a container is ready and when it should be replaced.
Guided phase lab
Do these in order. Each step should end with evidence before the next one starts.
- 01
Write a .dockerignore first so local node_modules, Git history, secrets, and build output do not enter context.
- 02
Create a multi-stage API Dockerfile separating dependencies/build/runtime artifacts.
- 03
Build with frozen lockfile and inspect image layers/size.
- 04
Run the container with runtime env vars and map the service port explicitly.
- 05
Add healthcheck/readiness behavior and test startup plus graceful stop.
- 06
Create a small compose setup only for local integration needs and explain what remains externally managed.
docker build -t taskflow-api:dev .
docker run --rm -p 4000:4000 --env-file .env taskflow-api:dev
docker ps
docker logs <container>
docker inspect <container>Predict what each command proves before running it. A command is useful only when its output answers a question.
Failures you should know how to diagnose
Copying .env into image
Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.
Running development server in production container
Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.
Huge build context invalidating caches
Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.
Container listens only on localhost internally
Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.
Lessons
The source chapters come first. Every phase now ends with a guided build, a debugging workshop, and an independent challenge so reading turns into transferable skill.
Container Mental Model Images Layers and Processes
Container Mental Model: Images, Layers, and Processes Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, o
Dockerfile Multi Stage Builds and Cache Design
Dockerfile Design: Multi-Stage Builds and Cache Efficiency Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secre
Monorepo pnpm and Turborepo Build Context
Monorepo, pnpm, and Turborepo Build Context Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or business
Next.js Standalone Production Image
Next.js Production Image with Standalone Output Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or busi
NestJS API Production Image
NestJS + Fastify Production Image Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or business responsib
Non Root Runtime and Image Hardening
Non-Root Runtime and Image Hardening Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or business respon
Environment Variables Secrets and Build Time Config
Environment Variables, Secrets, and Build-Time Configuration Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, sec
Healthchecks Graceful Shutdown and Readiness
Health Checks, Graceful Shutdown, and Readiness Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or busi
Docker Compose Local Integration Environment
Docker Compose for Local Integration Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or business respon
Migrations Volumes and Stateful Service Rules
Migrations, Volumes, and Stateful-Service Rules Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or busi
Image Testing Debugging and Common Failures
Image Testing, Debugging, and Common Failures Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or busine
Hands On Lab and Phase Exit
Hands-On Lab and Phase Exit Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or business responsibilitie
Guided Build Lab
Purpose Containerize the production API/web artifacts reproducibly with secure runtime configuration, small images, health checks, networking, and graceful shutdown.
Debugging Workshop
Goal Learn to diagnose this phase's failures systematically instead of reinstalling packages, changing random configuration, or copying a fix without understanding it.
Phase Synthesis & Independent Challenge
Mission Rebuild the capability of Phase 32 without following the exact code line-by-line. The goal is transfer: can you use the ideas when the variable names, UI, or route shape changes?
Mastery Capstone Lab
Integrate Phase 32 without following a transcript.
Exercises that increase independence
Write a .dockerignore first so local node_modules, Git history, secrets, and build output do not enter context.
Build with frozen lockfile and inspect image layers/size.
reproduce and diagnose — Copying .env into image.
deliver Dockerfiles and compose/dev verification that build and run TaskFlow services from clean inputs.
Can explain image vs container and Can build multi-stage image.
Do not leave the phase only because you reached the bottom
Phase exit criteria
Scenario and concept quiz
These questions test engineering choices rather than whether you remember a lesson title.
Reference files
Attempt the work first. Use snapshots to compare a checkpoint, not as a substitute for understanding.
reference/TaskFlow_Docker_Snapshot/.dockerignore
# Git / editor .git .github .vscode .idea # local dependencies and outputs **/node_modules **/.next **/dist **/coverage **/playwright-report **/test-results # secrets / local config .env .env.* !.env.example # misc
reference/TaskFlow_Docker_Snapshot/README.md
# TaskFlow Docker Snapshot This is a teaching/reference snapshot for Phase 32. Adapt paths to the exact final repository layout before production use. Production architecture keeps managed Supabase services external. `compose.yaml` uses local PostgreSQL only to demonstrate a repeatable local integration topology.
reference/TaskFlow_Docker_Snapshot/SOURCES.md
# Official sources used for Phase 32 - Docker multi-stage builds: https://docs.docker.com/build/building/multi-stage/ - Docker build best practices: https://docs.docker.com/build/building/best-practices/ - Docker build cache: https://docs.docker.com/build/cache/optimize/ - Docker Compose startup/readiness: https://docs.docker.com/compose/how-tos/startup-order/ - Next.js standalone output: https://nextjs.org/docs/app/api-reference/config/next-config-js/output
reference/TaskFlow_Docker_Snapshot/VERSION_LOCK.md
# Phase 32 version line - Node runtime image: Node 24 LTS line (`node:24-bookworm-slim`) - pnpm: 12.3.4 (course lock) - PostgreSQL local integration image: 18-alpine - Next.js: existing course lock (16.x) with `output: "standalone"` - NestJS: existing course lock (12.x) - Prisma: hard lock 7.9.1 Docker Desktop / Engine / Compose are environment tools rather than npm dependencies. Validate current stable releases on the machine used for the course.
reference/TaskFlow_Docker_Snapshot/apps/api/Dockerfile
# syntax=docker/dockerfile:1.7
FROM node:24-bookworm-slim AS base
ENV PNPM_HOME=/pnpm
ENV PATH=$PNPM_HOME:$PATH
RUN corepack enable && corepack prepare pnpm@12.3.4 --activate
WORKDIR /workspace
FROM base AS deps
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json ./
COPY apps/api/package.json apps/api/package.json
COPY packages packages
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm install --frozen-lockfile
FROM deps AS builder
COPY . .
RUN pnpm --filter api exec prisma generate
RUN pnpm --filter api build
RUN pnpm --filter api deploy --prod /out/api
reference/TaskFlow_Docker_Snapshot/apps/web/Dockerfile
# syntax=docker/dockerfile:1.7
FROM node:24-bookworm-slim AS base
ENV PNPM_HOME=/pnpm
ENV PATH=$PNPM_HOME:$PATH
RUN corepack enable && corepack prepare pnpm@12.3.4 --activate
WORKDIR /workspace
FROM base AS deps
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json ./
COPY apps/web/package.json apps/web/package.json
COPY packages packages
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm install --frozen-lockfile
FROM deps AS builder
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN pnpm --filter web build
FROM node:24-bookworm-slim AS runnerreference/TaskFlow_Docker_Snapshot/apps/web/next.config.phase32.ts
import path from "node:path";
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "standalone",
outputFileTracingRoot: path.join(__dirname, "../.."),
};
export default nextConfig;reference/TaskFlow_Docker_Snapshot/infra/compose.yaml
name: taskflow
services:
db:
image: postgres:18-alpine
environment:
POSTGRES_DB: taskflow
POSTGRES_USER: taskflow
POSTGRES_PASSWORD: taskflow_local_only
healthcheck:
test: ["CMD-SHELL", "pg_isready -U taskflow -d taskflow"]
interval: 5s
timeout: 3s
retries: 10
start_period: 10s
volumes:
- taskflow-db:/var/lib/postgresql/data
api:
build:reference/TaskFlow_Docker_Snapshot/infra/migration-runbook.md
# Migration runbook Production rule: run `prisma migrate deploy` once as an explicit deployment/release step before new API replicas begin serving traffic. Do not run it independently in every replica startup command. Local example from the repository root: ```powershell pnpm --filter api exec prisma migrate deploy ``` For a fully containerized local workflow, build a dedicated migration target/job that includes Prisma CLI and the schema, waits for PostgreSQL readiness, runs once, and exits successfully.
reference/TaskFlow_Docker_Snapshot/tests/docker-test-matrix.md
# Phase 32 verification matrix - [ ] `docker build` succeeds for web with the committed lockfile. - [ ] `docker build` succeeds for api with the committed lockfile. - [ ] Runtime processes run as non-root users. - [ ] Production images do not contain `.env`, `.git`, local `node_modules`, or source test output. - [ ] Web container serves the production Next.js build on port 3000. - [ ] API container serves `/health/live` on port 3001. - [ ] API readiness fails when PostgreSQL is unavailable and recovers when PostgreSQL is ready. - [ ] `docker compose up` uses `db` service DNS instead of localhost for API database access. - [ ] Database state survives recreation of the db container when the named volume remains. - [ ] SIGTERM produces a graceful NestJS shutdown. - [ ] Rebuilding after a source-only change reuses dependency-install cache. - [ ] Secrets are injected at runtime and not visible in image history.