A Dockerfile Is a Milk-Tea SOP: Build and Ship a Full-Stack Todos App
A Dockerfile turns a project into a single reproducible artifact that runs the same way in dev, test, and production, eliminating environment drift. Understanding the build-cache model and multi-stage builds directly cuts image size and CI minutes.
Dockerfiles work like a chain store's standard operating procedure: FROM selects the base, COPY brings in code, RUN installs dependencies, and CMD starts the service. Every instruction executes in order and caches its layer, so rebuilds are fast. The four-command pipeline—build, login, push, pull—turns that recipe into a portable image that runs identically on any machine.
A real todos full-stack project demonstrates the pattern across three pieces: a React frontend built with Vite and served by nginx, a NestJS backend compiled from TypeScript, and an nginx reverse proxy that makes frontend and backend same-origin to eliminate CORS issues in production. Each piece gets its own Dockerfile, and the frontend uses a multi-stage build to keep the final image lean.
Cross-origin handling splits into two strategies: nginx reverse proxy for production (all traffic on port 80, no browser CORS block) and backend CORS headers for local development. The article closes with a command quick-reference table and a question that bridges into Docker networking—what hostname should proxy_pass use when the backend sits inside a container network behind nginx.
The SOP analogy is unusually effective for Dockerfiles because both enforce deterministic, repeatable output by following a fixed sequence—deviation is the bug, not the feature.
Teaching Docker through a concrete full-stack project with separate frontend, backend, and proxy Dockerfiles exposes the real multi-service pattern early, rather than leaving learners stuck on single-container tutorials.
The article deliberately ends with an open question about container networking (localhost vs. service name in proxy_pass), which is the exact friction point that trips people moving from docker run to docker compose.