Dockerfiles and why they drift
A Dockerfile is the build recipe for a container image: a base image in FROM, then RUN, COPY, ENV, EXPOSE and friends executed top to bottom, often split into several stages so the final image carries only the build output. Docker, BuildKit, Podman and Buildah all read the same syntax, and Podman also accepts the name Containerfile. Because they are copied between projects and edited by people with different habits, Dockerfiles accumulate lowercase instructions, double spaces, JSON arrays without spaces and stray indentation. None of that breaks a build, but it makes reviews and diffs noisier than they need to be.
Running the formatter
Paste the file or drop it in. A first instruction of FROM or ARG followed by familiar instructions is enough for the format to be detected. Formatting happens as you type; Ctrl/Cmd+Enter forces a run and Ctrl/Cmd+K opens the command palette for downloading or copying the result.
The formatting engine is dprint-plugin-dockerfile, the Rust formatter from the dprint project, compiled to WebAssembly and executed in your browser. A small line checker runs before it to catch mistakes the formatter itself would let through. Build arguments, registry hostnames and anything else in the file are processed locally and are not uploaded. There are no settings to adjust: dprint’s Dockerfile style is fixed, and the toolbar indent does not apply.
What changes in the output
- Instructions such as
FROM,RUN,COPY,CMD,ENTRYPOINT,ENV,ARG,LABEL,HEALTHCHECK,ONBUILDandSHELLare uppercased, and so is theASin a stage name. - A few instructions, including
WORKDIR,USER,EXPOSE,ADDandVOLUME, keep the case you typed. Docker does not care, but if the rest of the file is uppercase, fix those by hand. - Exec-form arrays get a space after each comma:
CMD ["node","server.js"]becomesCMD ["node", "server.js"]. - Runs of spaces between arguments and flags collapse to one, while spaces inside quoted strings are left alone.
- Indentation in front of an instruction is removed, and several blank lines in a row become one.
ENVcontinuation lines are indented consistently. Continuation lines of aRUNcommand keep the indentation you gave them, so carefully alignedapt-get installpackage lists stay aligned.
Heredocs, comments and what is checked
BuildKit heredocs (RUN <<EOF … EOF and COPY <<EOF /etc/motd) are copied byte for byte, including tabs in a <<- heredoc, because their contents are a script or a file rather than Dockerfile syntax. Comment lines and parser directives such as # syntax=docker/dockerfile:1 stay where they are.
Before formatting, every line is checked for a known instruction. A typo like FORM or exposee is reported as an error and the file is not formatted, since Docker would refuse it too. An instruction other than ARG before the first FROM produces a warning. What is not checked: the shell commands inside RUN, image names, and whether a COPY --from stage exists. Two limitations to be aware of: a comment line placed between the lines of a multi-line RUN is flagged by the line checker even though BuildKit accepts it, and Windows Dockerfiles that use the escape parser directive to make the backtick their line-continuation character are not supported.
Examples
Multi-stage Go build written in lowercase
FROM, AS, COPY, RUN and ENTRYPOINT are uppercased and the entrypoint array is spaced; workdir and user keep their lowercase.
from golang:1.23 as builder
workdir /src
copy go.mod go.sum ./
run go mod download
copy . .
run CGO_ENABLED=0 go build -o /out/api ./cmd/api
from gcr.io/distroless/static
copy --from=builder /out/api /api
user nonroot
entrypoint ["/api","--port","8080"]
FROM golang:1.23 AS builder
workdir /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /out/api ./cmd/api
FROM gcr.io/distroless/static
COPY --from=builder /out/api /api
user nonroot
ENTRYPOINT ["/api", "--port", "8080"]
Python image with a RUN heredoc
The heredoc script is untouched, the ENV continuation is re-indented and the CMD array gains spaces.
# syntax=docker/dockerfile:1
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
RUN <<EOF
apt-get update
apt-get install -y --no-install-recommends curl
rm -rf /var/lib/apt/lists/*
EOF
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
CMD ["gunicorn","app:server","-b","0.0.0.0:8000"]
# syntax=docker/dockerfile:1
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
RUN <<EOF
apt-get update
apt-get install -y --no-install-recommends curl
rm -rf /var/lib/apt/lists/*
EOF
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
CMD ["gunicorn", "app:server", "-b", "0.0.0.0:8000"]
Node service with build arguments and a health check
ARG before FROM is allowed, the ${NODE_VERSION} reference is kept, and healthcheck and cmd become uppercase.
ARG NODE_VERSION=22
FROM node:${NODE_VERSION}-alpine
LABEL org.opencontainers.image.source="https://github.com/example/shop"
healthcheck --interval=30s CMD wget -qO- http://localhost:3000/health || exit 1
expose 3000
cmd ["node","server.js"]
ARG NODE_VERSION=22
FROM node:${NODE_VERSION}-alpine
LABEL org.opencontainers.image.source="https://github.com/example/shop"
HEALTHCHECK --interval=30s CMD wget -qO- http://localhost:3000/health || exit 1
expose 3000
CMD ["node", "server.js"]
Common errors and how to fix them
| Error | Cause | Fix |
|---|---|---|
Unknown instruction 'FORM' | An instruction is misspelt, or a line that should continue the previous one lost its trailing backslash. | Correct the spelling, or add \ at the end of the line above so the text belongs to the previous instruction. |
RUN before the first FROM | A build step appears before any base image is chosen. Only ARG may come before the first FROM. | Move the instruction below FROM, or turn it into an ARG if it only defines a build-time value. |
Unknown instruction 'echo' | A comment line sits between the lines of a multi-line RUN, so the checker sees the next line as the start of a new instruction. | Move the comment above the RUN instruction; the build behaves the same and the file formats cleanly. |
Unknown instruction '&&' | A command was split over lines without a trailing backslash, or the file is a Windows Dockerfile whose escape directive makes the backtick the continuation character. | End every continued line with a backslash. Files that change the escape character cannot be formatted here. |
Frequently asked questions
Does Dockerfile instruction case matter?
No. Docker treats instructions case-insensitively, but uppercase is the documented convention and makes instructions stand out from their arguments.
Does this lint my Dockerfile like hadolint?
Only lightly. It catches unknown instructions and steps placed before FROM. For best-practice rules such as pinning package versions, run hadolint as well.
Will it change my RUN commands?
The command text stays the same apart from collapsing repeated spaces outside quotes. Continuation lines and heredoc bodies keep their layout.
Can I format a Containerfile or docker-compose.yml here?
A Containerfile uses the same syntax, so yes. docker-compose.yml is YAML; use the YAML formatter for that.
Why did my file not format at all?
An unknown instruction stops formatting so a typo is not hidden. Fix the reported line and the output appears.