Home › Developer Tools › Dockerfile Linter

Dockerfile Linter

Paste a Dockerfile and get an instant review against 38 best-practice rules: unpinned or latest base images, apt-get update in its own layer, leftover package caches, missing non-root USER, shell-form CMD, secrets in ENV and more. Every finding links to its line and explains why it matters and how to fix it.

Last updated:

Rules (0 enabled)

Untick a rule to ignore it. Your choice is remembered in this browser. You can also add # lint-ignore: DF201 on the line above an instruction.

–
Paste a Dockerfile
    Advertisement
    Advertisement

    How to use the Dockerfile Linter

    1. Paste your Dockerfile into the editor, upload it, or load one of the samples.
    2. Read the score and the counts of errors, warnings and suggestions; the stage cards show how many layers each stage creates.
    3. Open each finding: click the line number to jump to it and expand Why it matters for the reasoning and a corrected example.
    4. Fix and re-check: the Dockerfile is linted again as you type.
    5. Tune the rules if a check does not fit your project, then copy the report for a code review or ticket.

    Rule reference

    Rules are grouped by severity. Errors break the build or behave differently than intended, warnings affect security, size or reproducibility, and suggestions are good habits.

    CodeRuleTypical fix
    DF101FROM must be the first instructionOnly ARG may come before FROM
    DF102Unknown instructionFix the typo or restore the missing \ on the line above
    DF103Invalid JSON in exec formCMD ["npm", "start"] with double quotes
    DF104 / DF105Duplicate stage name / unknown COPY --fromUnique AS name; refer to earlier stages only
    DF106Several sources need a directory destinationCOPY a.txt b.txt ./
    DF107 / DF108Invalid EXPOSE port / relative WORKDIREXPOSE 8080, WORKDIR /app
    DF201 / DF202Unpinned or :latest base imageFROM python:3.12-slim
    DF203Container runs as rootUSER app in the final stage
    DF204 – DF208apt-get: update with install, cache cleanup, -y, apt vs apt-get, no upgradeapt-get update && apt-get install -y --no-install-recommends … && rm -rf /var/lib/apt/lists/*
    DF209 / DF210apk and yum/dnf cachesapk add --no-cache, dnf clean all
    DF211 / DF216sudo, chmod 777USER switches, COPY --chown
    DF212 / DF313ADD for local files, unverified URLsCOPY; ADD --checksum=sha256:…
    DF213More than one CMD or ENTRYPOINTKeep only the last one
    DF214MAINTAINER is deprecatedLABEL org.opencontainers.image.authors=…
    DF215Secret in ENV or ARGRuntime variables or RUN --mount=type=secret
    DF217Empty line in a continuationRemove the blank line
    DF301 – DF313Suggestions: no-install-recommends, pip cache, WORKDIR vs cd, exec form, combined RUNs, cache-friendly COPY order, pipefail, ENV key=value, uppercase, HEALTHCHECK, npm ci, layer countSee the explanation under each finding

    A cache-friendly Dockerfile layout

    Docker rebuilds a layer when the instruction or the files it copies change, and every layer after it. Order instructions from least to most frequently changed:

    1. Base image with a pinned tag, and system packages installed and cleaned in one RUN.
    2. Dependency manifests only: package.json and package-lock.json, requirements.txt, go.mod and go.sum.
    3. Dependency install: npm ci, pip install --no-cache-dir -r requirements.txt, go mod download.
    4. Source code: COPY . ., with a .dockerignore that excludes .git, node_modules and build output.
    5. Build step, ideally in a separate stage, then copy only the result into a small runtime image.
    6. Runtime settings: USER, EXPOSE, HEALTHCHECK and an exec-form CMD or ENTRYPOINT.

    With this order, editing a source file reuses the cached dependency layers and the rebuild takes seconds instead of minutes.

    Frequently asked questions

    What does a Dockerfile linter check?

    It reads each instruction and compares it with widely recommended Dockerfile practices: reproducible base images (pinned tags), small layers (package caches removed in the same RUN), security (a non-root user, no secrets in ENV, no chmod 777), correct syntax (valid JSON in exec form, known instructions, valid EXPOSE ports) and build-cache efficiency (dependency files copied before the source).

    Why should apt-get update and apt-get install be in the same RUN?

    Docker caches every RUN instruction as a layer. If apt-get update has its own RUN, that layer is reused on later builds even after you add packages to the install line, so apt-get works with old package lists and may fail or install outdated versions. Putting both in one RUN, followed by rm -rf /var/lib/apt/lists/*, refreshes the lists and removes them in the same layer.

    Why does the linter want a USER instruction?

    Unless a Dockerfile sets USER, the container process runs as root. If the application is compromised, root inside the container makes escaping to the host or tampering with mounted files easier. Create an unprivileged user, install packages first, then switch with USER in the final stage.

    What is the difference between shell form and exec form?

    Shell form (CMD python app.py) runs the command through /bin/sh -c, so your program is a child of the shell and does not receive SIGTERM when the container stops; Docker waits 10 seconds and then kills it. Exec form (CMD ["python", "app.py"]) starts the program directly as PID 1, so it can shut down cleanly.

    How many layers is too many?

    Docker supports up to 127 layers in an image, but well before that many layers make pulls slower and images harder to inspect. Only RUN, COPY and ADD add filesystem layers. The linter suggests combining consecutive RUN instructions and reports the final stage when it creates more than 15 layers. Multi-stage builds help most, because only the final stage ends up in the image.

    Is this the same as hadolint?

    No. This is an independent, browser-based linter with its own rule set (codes DF101 to DF313) inspired by Docker's official best-practice guidance. It does not run ShellCheck on RUN commands. For CI pipelines, a command-line linter is a good complement; this tool is handy for quick reviews and learning why each rule exists.

    Can I ignore a rule for one line?

    Yes. Put a comment such as # lint-ignore: DF201 on the line directly above the instruction to skip that rule there, or untick the rule in the Rules list to turn it off everywhere. The rule list is remembered in your browser.

    Are all the tools on FreeToolCabin tested for quality and accuracy?

    Yes! Every tool on our site undergoes automated Q/A testing in real browser environments to ensure high precision, correct output, and zero errors. If you happen to spot a bug or have a suggestion, please contact us at [email protected] and our team will review it right away.

    Related tools

    Dockerfile GeneratorGenerate a production Dockerfile and .dockerignore for Node, Python, Go or a static nginx site.Docker Compose ValidatorCheck a docker-compose.yml for YAML errors, schema mistakes, broken references and deprecated keys.Dockerignore GeneratorBuild a .dockerignore from Node, Python, Go and Java templates, plus your own entries.Chmod CalculatorConvert Linux file permissions between checkboxes, octal (755) and symbolic (rwxr-xr-x) notation.QR Code GeneratorMake QR codes for links, Wi-Fi, email and more.Barcode GeneratorCreate Code 128, EAN-13, UPC-A, EAN-8, Code 39 and ITF-14 barcodes as PNG or SVG.UUID GeneratorGenerate UUID v4 and v7 / GUIDs in bulk and copy or download them.Schema Markup Generator (JSON-LD)Create JSON-LD structured data for FAQ, Product, Article and more.Htaccess & Nginx Redirect GeneratorBuild 301 redirects for .htaccess, Nginx and Netlify or Cloudflare _redirects.Fake Data GeneratorGenerate mock data as JSON, CSV or SQL.Random String GeneratorGenerate secure random strings and tokens in bulk with any length and character set.API Key GeneratorCreate secure API keys and secrets with prefixes, checksums and SHA-256 hashes for storage.MIME Type LookupFind the MIME type for any file extension, or the extensions for a MIME type, in 400+ entries.Cron Expression GeneratorBuild crontab schedules visually, read them in plain English and see the next run times.URL Slug GeneratorTurn titles into clean, SEO-friendly URL slugs: accents, stop words, separators and bulk lines.JSON Schema GeneratorTurn sample JSON into a draft 2020-12 JSON Schema with types, required fields and formats.Gitignore GeneratorBuild a .gitignore from 50+ templates for languages, frameworks, IDEs and OS, merged and deduped.License GeneratorCreate a LICENSE file for MIT, Apache, GPL, BSD, ISC, MPL or Unlicense with your name and year.ULID GeneratorGenerate sortable ULIDs and UUID v7 in bulk, monotonic option, and decode their timestamps.Htpasswd GeneratorCreate .htpasswd entries with bcrypt, APR1-MD5 or SHA-1 for Apache and Nginx basic auth.Placeholder Image GeneratorCreate placeholder images in any size, color and text as PNG, JPG, WebP, SVG or data URI.Ads.txt GeneratorCreate or validate ads.txt and app-ads.txt files: seller lines, cert IDs and variables.Docker Run to Compose ConverterConvert docker run commands to docker-compose.yml, or a compose file back to docker run.HTML Boilerplate GeneratorTick the options you need and get a clean HTML5 starter template with meta, OG tags and CSS reset.JSON to Zod SchemaInfer a Zod (or Yup) schema from sample JSON with optional, nullable and z.infer types.Linux Commands Cheat SheetSearchable Linux and bash command reference with flags explained, examples and copy buttons.LLMs.txt GeneratorBuild an llms.txt file for AI crawlers: summary and link sections, import from your sitemap.Nano ID GeneratorGenerate secure Nano IDs with custom alphabet, length and count, plus a collision calculator.Nginx Config GeneratorBuild an nginx server block: static site, SPA, reverse proxy or PHP, with SSL, gzip and redirects.OpenAPI / Swagger ViewerView OpenAPI 2/3 JSON or YAML as interactive API docs with validation and an endpoint list.package.json GeneratorFill a form and get a valid, npm-ready package.json with scripts, dependencies and checks.PKCE Code Challenge GeneratorGenerate an OAuth 2.0 PKCE code_verifier and S256 code_challenge, build auth URLs, verify pairs.README GeneratorFill in a form and get a polished README.md with badges, install, usage and license, live preview.Regex GeneratorBuild regular expressions visually from blocks or presets (email, date, phone) and test them live.Commit Message GeneratorBuild Conventional Commit messages with type, scope, body, breaking change and issue refs.Database Schema DesignerDesign tables and relationships visually, then export SQL for MySQL, PostgreSQL or SQLite.Docker Compose GeneratorBuild a docker-compose.yml with a form: services, ports, volumes, env, healthchecks and presets.Dummy File GeneratorCreate test files of an exact size in KB, MB or GB with zeros, random bytes or text.Product Schema GeneratorBuild Product JSON-LD with price, availability, brand, GTIN, ratings and reviews.Question Keyword GeneratorFind the questions people ask about a topic, grouped by who, what, why, how, can and more.Recipe Schema GeneratorCreate Recipe JSON-LD with ingredients, steps, prep and cook times, nutrition and ratings.Security Headers GeneratorPick HSTS, CSP, frame, referrer and permissions options and get Apache, Nginx, Netlify or Cloudflare config.SKU GeneratorBuild consistent SKUs from brand, category, size and color, then export every variant as CSV.Typography Scale GeneratorBuild a modular type scale from a base size and ratio, then copy CSS variables or a Tailwind config.WordPress Salt GeneratorGenerate fresh WordPress security keys and salts for wp-config.php, .env or Docker in one click.ANSI Color Code GeneratorStyle terminal text with 16, 256 or RGB colors and get escape codes for bash, Python, JS and C.Apache Virtual Host GeneratorCreate an Apache VirtualHost config with SSL, redirects, reverse proxy or PHP-FPM in seconds.Bash Prompt GeneratorDrag and drop a custom PS1 prompt for bash or zsh with colors, git branch and a live preview.Changelog GeneratorTurn Conventional Commit messages into a grouped Keep a Changelog Markdown file per version.cURL Command BuilderBuild curl commands from a form: method, headers, query, JSON or form body, auth and flags.Docker Compose to KubernetesConvert docker-compose.yml into Kubernetes Deployment, Service, ConfigMap and PVC manifests.ESLint Config GeneratorGenerate a flat eslint.config.js for JavaScript, TypeScript, React or Node with rule presets.Git Branch Name GeneratorTurn a ticket ID and title into a clean, valid git branch name like feature/PROJ-12-add-login.GitLab CI Config GeneratorGenerate a .gitlab-ci.yml with stages, jobs, images, cache, artifacts and rules from templates.Jinja2 Template TesterRender Jinja2 templates with YAML or JSON variables using real Jinja2, with clear error lines.JSON Schema Mock Data GeneratorGenerate realistic sample JSON from a JSON Schema: formats, patterns, $ref, seeds and counts.Kubernetes Secret GeneratorCreate Kubernetes Secret YAML from key/value pairs or .env with auto base64, or decode one.Kubernetes YAML ValidatorValidate Kubernetes manifests against the API schema of a chosen version, with error paths.Prettier Config GeneratorToggle Prettier options, preview formatted code live and copy your .prettierrc file.Quartz Cron GeneratorBuild and explain Quartz and Spring cron expressions with seconds, ?, L, W and #, plus next fire times.README Badge GeneratorCreate Shields.io-style README badges for license, version, build and custom labels.Systemd Service File GeneratorCreate a systemd .service unit with ExecStart, user, restart policy, environment and hardening.tsconfig.json GeneratorBuild a tsconfig.json with target, module, strict checks and path aliases, each option explained.Access Log AnalyzerAnalyze Apache and Nginx access logs: top URLs, IPs, status codes, bots and traffic charts.Regex String GeneratorGenerate random test strings that match any regular expression, checked against the real regex.ASCII Table GeneratorTurn CSV or pasted cells into plain-text tables: MySQL, Markdown, Unicode box and reST styles.FFmpeg Command GeneratorPick a task and options, get the exact ffmpeg command with every flag explained.Folder Tree GeneratorTurn a local folder or an indented list into an ASCII directory tree for your README.
    See all 85 Code Generators & Builders →