What a Dockerfile actually is
A Dockerfile is a plain-text recipe that tells Docker how to build a container image. Each line is an instruction — FROM, COPY, RUN, CMD. Docker processes the instructions top to bottom, and most of them produce a new layer on top of the previous state. The resulting image is the sum of all those layers.
The syntax is simple, but remembering the right combination for a clean production image is a chore. This generator gives you a form, picks sensible defaults based on a template (Node.js, Python, Nginx, Go, Rust), and renders a valid Dockerfile you can paste into ./Dockerfile and build immediately.
Each instruction explained
- FROM — the base image. Pick an official tag with a specific version (e.g.
node:20-alpine, notnode:latest) so your builds are reproducible. Alpine variants are small but can have glibc compatibility issues; slim variants are usually safer for general-purpose apps. - WORKDIR — the directory subsequent instructions run in. Setting it to
/appis convention. Unlikecdin a shell,WORKDIRpersists across instructions. - COPY src dest — copies from the build context (your host) into the image. Use
COPY, notADD, unless you specifically need the tar-unpacking or URL-fetching behavior ofADD. Also: copy dependency manifests before source so layer caching works. - RUN — executes a shell command during build. Each
RUNcreates a new layer, so chain related commands with&&to keep the image small. - ENV — sets environment variables that persist at runtime. Also useful for forcing language-runtime defaults (e.g.
PYTHONUNBUFFERED=1,NODE_ENV=production). - EXPOSE — documentation-only in Docker (doesn't actually publish a port). But orchestrators and tools read it, so it's still worth including.
- USER — drops root privileges. Running as a non-root user in production is a basic security win;
node:20-alpinealready ships with anodeuser for this purpose. - CMD — the default command run when the container starts. Two forms: exec (a JSON array like
["node", "index.js"]) is preferred — it doesn't start a shell and forwards signals correctly to your app. Shell form (plain string) wraps your command in/bin/sh -c, which is convenient for one-liners but breaks graceful shutdown. - ENTRYPOINT — the immutable part of the container's startup command. When both
ENTRYPOINTandCMDare set, CMD becomes default arguments to ENTRYPOINT, which users can override ondocker run.
Best practices this generator bakes in
- Pinned base image tags. Templates use specific versions (
node:20-alpine,python:3.12-slim) rather thanlatest, becauselatestis a moving target and your CI will fail at unexpected times. - Layer-cache-friendly ordering. The Node template copies
package*.jsonand runsnpm cibefore copying source. If only your source changes, Docker skips the dependency-install layer on rebuild. - Production-only installs.
npm ci --omit=devandpip install --no-cache-dirkeep images small. - Non-root USER. The Node template drops to the
nodeuser beforeCMD, so the app can't write outside its working dir. - Exec-form CMD. All templates use exec form so your process can receive
SIGTERMcorrectly during container shutdown.
Building and running your image
Once you've copied the generated Dockerfile into your project root, build and run with:
docker build -t my-app . docker run -p 3000:3000 my-app
The -p 3000:3000 maps the EXPOSEd container port to your host. Add a .dockerignore next to your Dockerfile so node_modules, .git, and build artifacts don't slow your builds — COPY . . will otherwise drag them into the image.
Related generator tools on CodeBoxTools
- Cron Expression Generator — build schedules for background jobs or container cron sidecars.
- UUID Generator — generate v4 or v7 UUIDs for container labels or request IDs.
- Password Generator — strong passwords for database or registry credentials.
- JSON Comments Stripper — clean up
devcontainer.jsonand other JSONC configs.