SysAdmin Tools

Dockerfile Linter

Check your Dockerfile against 15 security and best practice rules. Get a score, grade, and concrete suggestions to fix every issue found.


Paste your Dockerfile above and click ‘Lint Dockerfile’

15 rules checked · security · size · best practices

A Dockerfile linter analyses your Dockerfile against a ruleset of security guidelines and best practices, flagging issues before they end up in a production image. Writing a working Dockerfile is straightforward — writing one that is secure, small, and efficient requires knowing dozens of best practices that are easy to overlook under deadline pressure.

Common Dockerfile mistakes include using the latest tag (which silently pulls breaking changes on the next build), running the container as root (which gives any exploit full system access inside the container), installing packages without cleaning the apt cache (which bloats the image), and hardcoding secrets like API keys and passwords directly in ENV instructions (which embeds them permanently in every image layer). Our Dockerfile best practices checker catches all of these and more, scoring your file from 0 to 100 and assigning a letter grade.

The linter checks fifteen rules covering security, image size optimisation, and correctness. Each issue includes the exact line number, a severity level (error, warning, or informational), and a concrete suggestion showing the corrected syntax. The score calculation weights errors heavily — a single hardcoded secret deducts 15 points — so the grade reflects real risk, not just style preferences.

The tool runs completely in your browser via an API call to a serverless function — your Dockerfile content is processed and immediately discarded, never stored. It is an alternative to running hadolint locally and requires no Docker installation, no CLI tools, and no configuration.

How to Use the Dockerfile Linter

  1. 1

    Paste your Dockerfile content

    Open your Dockerfile in any text editor, select all (Ctrl+A), copy, and paste into the text area. Alternatively click "Load Example" to see a sample Dockerfile with intentional issues that demonstrates what the linter catches.

  2. 2

    Click Lint Dockerfile

    The tool sends your Dockerfile to the linter API, which parses it line by line and runs all fifteen rule checks. Results appear within a second.

  3. 3

    Review your score and grade

    The summary card shows your score out of 100 and a letter grade (A+ to F). Below it, issues are listed sorted by severity — errors first, then warnings, then informational suggestions.

  4. 4

    Read each issue and suggestion

    Each issue card shows the line number, the rule that fired, a plain-English message explaining the problem, and a highlighted suggestion box with the correct syntax or approach to fix it.

  5. 5

    Fix issues and re-lint

    Apply the suggestions to your Dockerfile, paste the updated content, and lint again. Iterate until you reach an A or A+ grade before building and pushing the image.

Understanding Dockerfile Lint Results

Each issue returned by the linter has four key fields. The Line number points you directly to the problematic instruction — click to it in your editor immediately. The Severity classifies the issue: an error represents a security risk or correctness problem that should always be fixed, a warning is a significant best practice violation that impacts security or image size, and info is an optimisation suggestion that improves the image but may not apply to every project. The Score starts at 100 and deducts 15 points per error, 8 points per warning, and 3 points per informational finding, with a floor of 0. The Grade maps the score to a letter: A+ (90–100), A (80–89), B (70–79), C (50–69), and F (below 50). A file with one hardcoded secret (−15) and three warnings (−24) would score 61 — a C grade — even with no other issues.
FieldDescription
LineThe 1-based line number in your Dockerfile where the issue was detected.
Severityerror = security/correctness risk; warning = best practice violation; info = optimisation suggestion.
RuleA short machine-readable identifier for the rule that fired (e.g. latest-tag, root-user, exposed-secrets).
MessageA plain-English description of what the linter found and why it is a problem.
SuggestionA concrete fix showing the corrected Dockerfile syntax or approach to resolve the issue.
ScoreA 0–100 numeric score. Start at 100, subtract 15 per error, 8 per warning, 3 per info finding.
GradeA+ (90–100), A (80–89), B (70–79), C (50–69), F (0–49).

Common Dockerfile Linting Use Cases

Security audit before pushing to a registry

Run the linter before every docker build and push. Catch hardcoded secrets, root user configurations, and exposed sensitive files before they land in your image registry and get deployed to production where they become a live vulnerability.

Reduce image size for faster deploys

Bloated images slow down CI/CD pipelines, increase pull times in Kubernetes, and cost more storage. The linter flags uncleaned apt caches, unchained RUN commands that add unnecessary layers, and opportunities to introduce multi-stage builds.

Onboarding and code review

Share the linter link with new engineers learning Docker. Paste a Dockerfile from a pull request and instantly explain why a specific pattern is problematic — the rule names and suggestions provide a structured teaching moment faster than a written comment.

Enforce standards across multiple projects

Run the Dockerfile linter as part of CI. If the score drops below a threshold (e.g. grade B or lower), fail the build. This enforces consistent quality standards across all teams and Dockerfiles in your organisation without manual review.

Dockerfile Linter — Frequently Asked Questions

What is a Dockerfile linter?
A Dockerfile linter is a static analysis tool that reads your Dockerfile and checks it against a set of best practice rules without running a build. It flags security vulnerabilities, inefficiencies, and common mistakes — such as using the latest tag, running as root, or hardcoding secrets — and provides specific suggestions for fixing each issue. Linting catches problems before they reach a running container.
Why should I avoid using the latest tag in a Dockerfile?
The latest tag is a moving target — it resolves to a different image version every time you pull. This means two builds of the same Dockerfile weeks apart can produce different images with different OS packages, library versions, and behaviour. Pin to a specific version like node:20-alpine or python:3.12-slim to make builds reproducible and prevent silent breakage when the upstream image updates.
How do I run a Docker container as a non-root user?
Add a USER instruction near the end of your Dockerfile, after installing packages but before CMD. For Node.js images that ship with a node user: USER node. For other images, create one first: RUN groupadd -r appgroup && useradd -r -g appgroup appuser then USER appuser. Running as non-root means that if an attacker exploits a vulnerability in your app, they get a low-privilege user rather than root access to the container filesystem.
What is the difference between ADD and COPY in a Dockerfile?
COPY simply copies files or directories from the build context into the image — what you see is what you get. ADD does the same but also auto-extracts tar archives and can fetch files from URLs. The rule of thumb: always use COPY for local files. Only use ADD when you specifically need the extra features (URL fetching or tar auto-extraction). ADD with a local file source hides the intent, while COPY makes the operation obvious.
How do I reduce Docker image size?
The most effective techniques are: use a minimal base image (alpine or slim variants), chain RUN commands with && to minimise layers, clean package manager caches in the same RUN step (rm -rf /var/lib/apt/lists/*), use multi-stage builds to exclude build tools from the final image, use COPY --from to pull only compiled artifacts, and add a .dockerignore file to exclude node_modules, .git, and test files from the build context.
What is a multi-stage Docker build?
A multi-stage build uses multiple FROM instructions in one Dockerfile. The first stage (the "builder") installs compilers, build tools, and dependencies, then compiles the application. The second stage starts from a minimal base image and uses COPY --from=builder to bring in only the compiled binary or artifacts. This keeps build tools out of the final image, dramatically reducing its size. For example a Go app might go from 800 MB (with Go compiler) to 10 MB (binary only).
Why should I combine RUN commands in a Dockerfile?
Each RUN instruction creates a new image layer. Docker stores all layers permanently, so if you install a package in one RUN and delete files in another, the deleted files still exist in the earlier layer and contribute to the total image size. Chaining commands with && in a single RUN ensures install, configure, and cleanup happen in one atomic layer. Fewer layers also means faster image pulls and pushes.
What is a HEALTHCHECK in a Dockerfile?
The HEALTHCHECK instruction tells Docker how to test whether the container is still working correctly. Docker periodically runs the health check command (typically a curl or wget request to a health endpoint) and marks the container as healthy or unhealthy based on the exit code. Container orchestrators like Kubernetes and Docker Swarm use this status to route traffic away from unhealthy containers and restart them automatically. Without HEALTHCHECK, Docker only knows if the process is running, not if it is responding correctly.
How do I avoid hardcoding secrets in a Dockerfile?
Never use ENV PASSWORD=mysecret or ARG API_KEY=abc123 with real values in a Dockerfile — these values are embedded in every image layer and visible in docker inspect and image history. Instead, pass secrets at runtime with -e PASSWORD=$PASSWORD or use Docker BuildKit secret mounts (--mount=type=secret) for build-time secrets. For Kubernetes, use Secrets objects injected as environment variables. The Dockerfile should only reference the variable name, never the value.
What is .dockerignore and why do I need it?
A .dockerignore file works like .gitignore but for Docker builds. It lists files and directories that should be excluded from the build context sent to the Docker daemon. Without it, COPY . . sends your entire project directory to the daemon — including node_modules (which can be gigabytes), .git history, test files, and local .env files. A good .dockerignore file keeps the build context small, speeds up builds, and prevents sensitive files from accidentally entering the image.

Related Tools