Best-practice linter for Dockerfiles

Best-practice Dockerfile lint.

Lint a Dockerfile against common best practices: pinned base image, apt cleanup, USER, WORKDIR, COPY vs ADD, deprecated MAINTAINER, etc. Pure browser; no login.

Findings (6)

  • warnline 1from-latest-tag

    Pin a specific version; avoid `alpine:latest` floating tag.

  • warnline 2maintainer-deprecated

    MAINTAINER is deprecated; use a LABEL instead.

  • warnline 3apt-cleanup

    Clean apt lists after install to keep the layer small.

  • infoline 4add-vs-copy

    Use COPY for local files; reserve ADD for URL or tar auto-extract.

  • warnline 5user-root

    Running as root; create and switch to a non-root USER.

  • infoline 6workdir-not-set

    No WORKDIR directive; consider setting one to make paths predictable.

Dockerfile best practices, checked line by line

A Dockerfile that works is not necessarily a good one. Images built from floating tags change under you, containers that run as root turn a small bug into a full compromise, and careless layer ordering makes builds slow and images large.

Paste a Dockerfile and this linter points out common problems with the line number and a short explanation: unpinned base images, missing USER and WORKDIR, apt caches left in the image, ADD used for local files, plain http:// downloads, shell-form commands and more.

How to use it

  1. Paste your Dockerfile into the box.
  2. Read the list of findings; each has a line number and a severity: warn or info.
  3. Fix the warnings first; they cover security and reproducibility.
  4. Consider the info items, which are style and size improvements.

Example: a quick first Dockerfile

Input
FROM node:latest
RUN apt-get update && apt-get install -y curl
ADD . /app
CMD npm start
Output
1 warn from-latest-tag
1 info from-distroless-or-slim
2 warn apt-cleanup
3 info add-vs-copy
5 warn user-not-set
5 info workdir-not-set

Four lines, six findings: the image floats, keeps the apt cache, copies with ADD, and runs as root from an unpredictable working directory.

Pin, slim down and clean up

Pin the base image to a version, such as node:22.11-bookworm-slim, so a rebuild next month produces the same image; for full reproducibility pin the digest too. Slim and Alpine variants leave out compilers and tools you do not need at runtime, which reduces size and attack surface.

Install packages and clean the package cache in the same RUN instruction: RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/*. Each instruction creates a layer, and files deleted in a later layer still take up space in the earlier one.

Do not run as root

Containers run as root unless told otherwise. If an attacker exploits the application, root inside the container makes escaping to the host and tampering with mounted files far easier. Create an unprivileged user and switch to it with USER before the final CMD; official images such as node already include a node user.

COPY, ADD and the command form

COPY does one predictable thing: copy files from the build context. ADD also downloads URLs and unpacks archives automatically, which can surprise you, so use it only when you want that. Write CMD and ENTRYPOINT in exec form, CMD ["node", "server.js"], so the process receives stop signals directly instead of through a shell and shuts down cleanly.

Questions

Is this a replacement for hadolint?

No. It checks a focused set of common rules in the browser. Hadolint checks many more rules and also lints the shell commands inside RUN; use it in CI.

Does it build or run my Dockerfile?

No. It only reads the text. Nothing is executed or uploaded.

Why is a missing WORKDIR only info?

Images still work without it, but paths become relative to /, which makes later instructions and debugging harder to follow.