Stage 4 · Provision
Building Images
Build Arguments & Metadata
Use ARG, ENV, LABEL, target stages, build contexts, and reproducible version metadata.
ARG vs ENV
ARG and ENV both set variables, but they have different scopes. ARG is available only during the build process — it is not present in the running container. ENV is available both during build and at runtime. Understanding this distinction prevents configuration errors.
| Feature | ARG | ENV |
|---|---|---|
| Available during build | Yes | Yes |
| Available at runtime | No | Yes |
| Overridable at build time | Yes (--build-arg) | Yes (--env) |
| Overridable at run time | No | Yes (-e) |
| Visible in image inspect | No | Yes |
Build Arguments
ARG lets you parameterize your Dockerfile. Pass values at build time to customize the build without modifying the Dockerfile. This is useful for version pinning, feature flags, and platform-specific builds.
FROM node:20-alpine
ARG NODE_ENV=production
ARG APP_VERSION=1.0.0
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
ENV NODE_ENV=${NODE_ENV}
LABEL version=${APP_VERSION}
CMD ["node", "server.js"]Build with: docker build --build-arg NODE_ENV=development --build-arg APP_VERSION=2.0 . ARG values are not available after the build — they exist only during the build process.
Environment Variables
ENV sets environment variables that persist in the image and are available in the running container. Use ENV for application configuration that needs to be accessible at runtime, and ARG for values that only matter during the build.
FROM node:20-alpine
# These are available at build time AND runtime
ENV NODE_ENV=production
ENV PORT=3000
# This is only available during build
ARG BUILD_DATE
LABEL build-date=${BUILD_DATE}
WORKDIR /app
COPY . .
CMD ["node", "server.js"]ENV values are inherited by child processes and are visible in docker inspect. They can be overridden at runtime with docker run -e NODE_ENV=development.
ENV values are baked into the image metadata. Anyone can see them with docker inspect. Never use ENV for secrets — use BuildKit secret mounts or runtime environment variables instead.
Labels
Labels are key-value metadata attached to images. They provide information about the image without affecting its behavior. Use labels for version tracking, maintainer information, and integration with orchestration tools.
FROM node:20-alpine
LABEL maintainer="team@example.com"
LABEL description="Production API server"
LABEL org.opencontainers.image.source="https://github.com/org/app"
LABEL org.opencontainers.image.version="1.2.3"
LABEL org.opencontainers.image.created="2025-01-15"
WORKDIR /app
COPY . .OCI labels follow the org.opencontainers.image convention. These are recognized by registries like Docker Hub and GitHub Container Registry, which display them in the UI.
Target Stages
Multi-stage Dockerfiles can have multiple stages, and you can build any stage independently using the --target flag. This lets you create different variants of an image from the same Dockerfile — for example, a production image and a development image.
FROM node:20-alpine AS base
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM base AS development
RUN npm install -g nodemon
COPY . .
CMD ["nodemon", "server.js"]
FROM base AS production
COPY . .
RUN npm run build
USER node
CMD ["node", "dist/server.js"]Build the dev variant: docker build --target development -t myapp:dev . Build the prod variant: docker build --target production -t myapp:prod . Each target produces a different image from the same Dockerfile.
Build Context
The build context is the set of files Docker sends to the daemon when building. By default, it is the current directory. You can specify a different context or even use a Git repository URL. The context affects which files are available for COPY.
# Use current directory as context
docker build -t myapp .
# Use a different directory
docker build -t myapp -f Dockerfile /path/to/context
# Use a Git repository
docker build -t myapp https://github.com/org/app.git
# Use stdin (Dockerfile only, no build context)
docker build -t myapp - < DockerfileThe -f flag lets you specify a Dockerfile path separate from the context. This is useful when your Dockerfile is not in the root of the project.
Large build contexts slow down builds. A 500MB context takes seconds to transfer before building even starts. Use .dockerignore to exclude node_modules, .git, and other large directories.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.