docker-syntax-dockerfile
Quick Reference
Parser Directives
Parser directives MUST appear at the very top of the Dockerfile, before any instructions, blank lines, or comments.
| Directive | Purpose | Example |
|---|---|---|
# syntax=docker/dockerfile:1 |
Enable BuildKit features (heredocs, mounts, etc.) | ALWAYS include this |
| `# escape=`` | Change escape character (useful on Windows) | Optional |
# check=error=true |
Enable build-time lint checks (v1.8.0+) | Optional |
ALWAYS start every Dockerfile with # syntax=docker/dockerfile:1 to enable BuildKit extensions.
All 17 Instructions at a Glance
| Instruction | Purpose | Creates Layer? |
|---|---|---|
FROM |
Set base image, start build stage | Yes (base) |
RUN |
Execute command during build | Yes |
CMD |
Default container command (overridable) | No (metadata) |
ENTRYPOINT |
Container executable (persistent) | No (metadata) |
COPY |
Copy files from context or stage | Yes |
ADD |
Copy with URL download and tar extraction | Yes |
ENV |
Set persistent environment variable | Yes |
ARG |
Set build-time variable (not persisted) | No |
WORKDIR |
Set working directory | Yes |
EXPOSE |
Document container port | No (metadata) |
VOLUME |
Declare mount point | No (metadata) |
USER |
Set user for subsequent instructions | No (metadata) |
HEALTHCHECK |
Define container health test | No (metadata) |
LABEL |
Add image metadata | Yes |
SHELL |
Override default shell | No (metadata) |
STOPSIGNAL |
Set container stop signal | No (metadata) |
ONBUILD |
Deferred instruction for child images | No (metadata) |
Critical Warnings
NEVER use latest tag in FROM -- ALWAYS pin to a specific version (node:20.11-bookworm-slim) or digest for reproducibility.
NEVER store secrets in ENV or ARG -- they are visible in docker history. ALWAYS use RUN --mount=type=secret instead.
NEVER use ADD when COPY suffices -- ADD has implicit behaviors (auto-extraction, URL download) that make builds less predictable.
NEVER use shell form for ENTRYPOINT -- the application will NOT be PID 1 and will NOT receive signals for graceful shutdown.
NEVER separate apt-get update and apt-get install into different RUN instructions -- the update layer gets cached and becomes stale.
ALWAYS combine related RUN commands with && to minimize layers.
ALWAYS clean up package manager caches in the same RUN layer as the install.
Shell Form vs Exec Form
Three instructions support both forms: RUN, CMD, ENTRYPOINT.
| Form | Syntax | Shell Processing | Variable Expansion | Signal Handling |
|---|---|---|---|---|
| Shell | CMD command arg1 |
Yes (/bin/sh -c) |
Yes ($VAR works) |
App is NOT PID 1 |
| Exec | CMD ["command", "arg1"] |
No (direct exec) | No (use ENV for vars) |
App IS PID 1 |
ALWAYS use exec form for CMD and ENTRYPOINT in production images.
Use shell form for RUN when you need variable expansion, pipes, or command chaining.
CMD vs ENTRYPOINT Interaction Matrix
| No ENTRYPOINT | ENTRYPOINT (shell form) | ENTRYPOINT (exec form) | |
|---|---|---|---|
| No CMD | Error -- no command | /bin/sh -c entrypoint_cmd |
entrypoint_cmd |
| CMD (exec form) | cmd_executable args |
/bin/sh -c entrypoint_cmd (CMD ignored) |
entrypoint_cmd cmd_args |
| CMD (shell form) | /bin/sh -c cmd_string |
/bin/sh -c entrypoint_cmd (CMD ignored) |
entrypoint_cmd /bin/sh -c cmd_string |
Best practice pattern:
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["default-command"]
ENTRYPOINT(exec form) sets the fixed executable.CMD(exec form) provides default arguments, overridable viadocker run.- Shell form ENTRYPOINT ALWAYS ignores CMD -- NEVER combine them.
COPY vs ADD Decision Guide
| Use Case | Instruction | Why |
|---|---|---|
| Copy local files | COPY | Explicit, predictable, no side effects |
| Copy from build stage | COPY --from | Only option for multi-stage copies |
| Download remote file with checksum | ADD --checksum | Integrity verification built in |
| Clone a Git repository | ADD (Git URL) | Supports branch/tag/commit references |
| Extract a local tar archive | ADD | Auto-extracts tar, tar.gz, tar.bz2, tar.xz |
| Everything else | COPY | ALWAYS prefer COPY by default |
ALWAYS prefer COPY unless you specifically need ADD's extra features.
ENV vs ARG Comparison
| Property | ENV | ARG |
|---|---|---|
| Available during build | Yes | Yes |
| Available at runtime | Yes | No |
| Visible in final image | Yes (docker inspect) |
No |
| Visible in history | Yes | Yes (NEVER put secrets here) |
| Overridable | docker run --env |
docker build --build-arg |
| Scope | Current + subsequent stages | Current stage only |
| Creates layer | Yes | No |
| Survives FROM | Yes (inherited) | No (must re-declare) |
ALWAYS use ARG for build-time-only values (version numbers, build flags). ALWAYS use ENV for values needed at container runtime (PATH, config).
HEALTHCHECK Syntax
HEALTHCHECK [OPTIONS] CMD <command>
HEALTHCHECK NONE
| Option | Default | Description |
|---|---|---|
--interval=DURATION |
30s | Time between checks |
--timeout=DURATION |
30s | Max time for single check |
--start-period=DURATION |
0s | Grace period on startup |
--retries=N |
3 | Consecutive failures before unhealthy |
Exit codes: 0 = healthy, 1 = unhealthy, 2 = reserved (NEVER use).
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
ALWAYS set --start-period for applications with slow startup.
ONBUILD Triggers
ONBUILD ADD . /app/src
ONBUILD RUN /app/src/compile.sh
- NOT executed in the current build -- fires in child images using
FROM <this-image>. - Useful for language-stack base images.
- ONBUILD ONBUILD is NOT allowed (no chaining).
- ONBUILD FROM and ONBUILD MAINTAINER are NOT allowed.
RUN Mount Types (BuildKit)
| Mount Type | Purpose | Key Flags |
|---|---|---|
--mount=type=cache |
Persist package manager caches | target, sharing, id |
--mount=type=bind |
Mount context without COPY layer | target, from, source |
--mount=type=secret |
Access secrets without baking in | id, target, env |
--mount=type=ssh |
Forward SSH agent | id |
--mount=type=tmpfs |
Temporary filesystem | target |
See references/instructions.md for complete mount syntax and examples.
Variable Substitution
Supported in: ADD, COPY, ENV, EXPOSE, FROM, LABEL, STOPSIGNAL, USER, VOLUME, WORKDIR, ONBUILD.
NOT supported in: RUN exec form, CMD exec form, ENTRYPOINT exec form (use shell form or ENV).
| Modifier | Example | Result |
|---|---|---|
| Default value | ${VAR:-default} |
Use default if VAR unset |
| Alternate value | ${VAR:+alternate} |
Use alternate if VAR is set |
| Remove prefix | ${VAR#pattern} |
Remove shortest prefix match |
| Remove suffix | ${VAR%pattern} |
Remove shortest suffix match |
Reference Links
- references/instructions.md -- Complete syntax and parameters for all 17 instructions
- references/examples.md -- Production-ready Dockerfile examples for common scenarios
- references/anti-patterns.md -- Instruction misuse patterns with corrections