DOCKER / GUIDE

Docker build: the complete command guide

Tags, context, Dockerfile paths, build args, caching, and multi-stage builds — everything you need to know about docker build, with production-ready examples.

· 6 min read

The docker build command turns a Dockerfile into a runnable image. It looks simple — docker build . — but the full command has dozens of options that matter when you're building production images. Here's a practical reference you can actually use.

The basic build command

docker build -t myapp:latest .

Three things happen here:

  • -t myapp:latest — tags the image as myapp with version latest
  • . — the build context (current directory, containing the Dockerfile)
  • Docker looks for a file named Dockerfile in that directory by default

Using a custom Dockerfile name or path

If your Dockerfile has a different name or lives in a subdirectory, use -f:

docker build -f ./docker/Dockerfile.prod -t myapp:prod .

Common pattern: Dockerfile.dev for development with hot reload, and Dockerfile.prod for production with multi-stage optimization.

Multiple tags at once

You can tag the same image with multiple labels in a single build command:

docker build \
  -t myapp:latest \
  -t myapp:v1.2.3 \
  -t myapp:stable \
  -t registry.example.com/myapp:v1.2.3 \
  .

This is useful in CI pipelines where you want both a version tag (for rollbacks) and a latest tag (for convenience).

Build arguments (--build-arg)

Build args let you pass variables into the Dockerfile at build time:

docker build \
  --build-arg NODE_VERSION=20 \
  --build-arg BUILD_ENV=production \
  -t myapp:prod .

Your Dockerfile declares them with ARG:

ARG NODE_VERSION=18
FROM node:$NODE_VERSION

ARG BUILD_ENV
ENV NODE_ENV=$BUILD_ENV

Never pass secrets through --build-arg — they're baked into image history and visible with docker history. Use --secret instead (BuildKit feature):

DOCKER_BUILDKIT=1 docker build \
  --secret id=npmrc,src=$HOME/.npmrc \
  -t myapp .

Disabling the cache

By default, Docker caches each layer. To force a full rebuild (useful when debugging cache issues or upstream image changes):

docker build --no-cache -t myapp .

To pull the latest base image even if a cached version exists:

docker build --pull -t myapp .

Target a specific stage (multi-stage builds)

For multi-stage Dockerfiles, you can build just a specific stage with --target:

docker build --target builder -t myapp:debug .

Example multi-stage Dockerfile:

# Stage 1: build
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: runtime
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]

docker build --target builder builds only the first stage, useful for debugging or running tests against the full build environment.

Build for a different platform (ARM/AMD64)

If you're on an M1/M2 Mac (ARM) but deploying to x86 servers:

docker build --platform linux/amd64 -t myapp:prod .

Or build for multiple platforms at once using BuildKit:

docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t myapp:latest \
  --push .

Common flags cheat sheet

  • -t — tag the image
  • -f — specify Dockerfile path
  • --build-arg — pass build arguments
  • --no-cache — disable build cache
  • --pull — always pull base image
  • --target — build specific multi-stage target
  • --platform — target platform (amd64, arm64, etc.)
  • --progress=plain — verbose output (useful for CI)
  • --rm — remove intermediate containers (default: true)
  • --squash — squash layers into one (experimental)

Production best practices

  1. Always use multi-stage builds — smaller final images, fewer attack surfaces
  2. Pin base image versionsFROM node:20.11-alpine, not FROM node:latest
  3. Order layers by change frequency — put COPY package.json before COPY . for better caching
  4. Use .dockerignore — prevent node_modules, .git, and secrets from leaking into the image
  5. Run as non-rootUSER node at the end of your Dockerfile
  6. Use BuildKit — set DOCKER_BUILDKIT=1 for faster builds and secrets support

Building Docker images on bare metal is significantly faster than on virtualized cloud instances. Multi-stage builds with large dependencies (like ML models or full Node.js builds) can complete in minutes on dedicated hardware versus 15-30 minutes on shared cloud VMs.

SKIP THE COMMANDS

Or just ask Claude on your server.

BareMetalServer.ai includes a built-in web terminal with Claude Code. Skip the documentation lookups — tell Claude what you need and it runs the commands directly on your server.

"Check Ubuntu version and update all packages"
"Install Docker and pull the latest nginx image"
"Set up a cron job to backup my database every 6 hours"

Claude runs commands, explains what it did, and fixes errors automatically. No SSH client, no memorizing flags, no documentation lookups.

Deploy a bare metal server in 5 minutes.

Full root access, NVMe storage, up to 100TB bandwidth. From $449/mo. Cancel anytime.