A smarter Dockerfile linter that helps you build best practice Docker
images. The linter parses the Dockerfile into an AST and performs rules on
top of the AST. It stands on the shoulders of ShellCheck to lint
the Bash code inside RUN instructions.
🌐 Check the online version on
hadolint.github.io/hadolint

- How to use
- Install
- CLI
- Configure
- Non-Posix Shells
- Ignoring Rules
- Linting Labels
- Integrations
- Rules
- Develop
- Alternatives
You can run hadolint locally to lint your Dockerfile.
hadolint <Dockerfile>
hadolint --ignore DL3003 --ignore DL3006 <Dockerfile> # exclude specific rules
hadolint --trusted-registry my-company.com:500 <Dockerfile> # Warn when using untrusted FROM imagesDocker comes to the rescue, providing an easy way how to run hadolint on most
platforms.
Just pipe your Dockerfile to docker run:
docker run --rm -i hadolint/hadolint < Dockerfile
# OR
docker run --rm -i ghcr.io/hadolint/hadolint < Dockerfileor using Podman:
podman run --rm -i docker.io/hadolint/hadolint < Dockerfile
# OR
podman run --rm -i ghcr.io/hadolint/hadolint < Dockerfileor using Windows PowerShell:
cat .\Dockerfile | docker run --rm -i hadolint/hadolintYou can download prebuilt binaries for OSX, Windows and Linux from the latest
release page. However, if this does not work for you, please fall back to
container (Docker), brew or source installation.
On OSX, you can use brew to install hadolint.
brew install hadolintOn Windows, you can use scoop to
install hadolint.
scoop install hadolintOn distributions that have nix installed, you can use the hadolint
package to run ad-hoc shells or permanently install hadolint into
your environment.
As mentioned earlier, hadolint is available as a container image:
docker pull hadolint/hadolint
# OR
docker pull ghcr.io/hadolint/hadolintIf you need a container with shell access, use the Debian or Alpine variants:
docker pull hadolint/hadolint:latest-debian
# OR
docker pull hadolint/hadolint:latest-alpine
# OR
docker pull ghcr.io/hadolint/hadolint:latest-debian
# OR
docker pull ghcr.io/hadolint/hadolint:latest-alpineYou can also build hadolint locally. You need Haskell and the cabal
build tool to build the binary.
git clone https://github.com/hadolint/hadolint \
&& cd hadolint \
&& cabal configure \
&& cabal build \
&& cabal installIf you want the VS Code Hadolint extension to use Hadolint in a container, you can use the following wrapper script:
#!/bin/bash
dockerfile="$1"
shift
docker run --rm -i hadolint/hadolint hadolint "$@" - < "$dockerfile"hadolint --helphadolint - Dockerfile Linter written in Haskell
Usage: hadolint [-v|--version] [-c|--config FILENAME] [DOCKERFILE...]
[--file-path-in-report FILEPATHINREPORT] [--no-fail]
[--no-color] [-V|--verbose] [-f|--format ARG] [--error RULECODE]
[--warning RULECODE] [--info RULECODE] [--style RULECODE]
[--ignore RULECODE]
[--trusted-registry REGISTRY (e.g. docker.io)]
[--require-label LABELSCHEMA (e.g. maintainer:text)]
[--strict-labels] [--disable-ignore-pragma]
[-t|--failure-threshold THRESHOLD]
Lint Dockerfile for errors and best practices
Available options:
-h,--help Show this help text
-v,--version Show version
-c,--config FILENAME Path to the configuration file
--file-path-in-report FILEPATHINREPORT
The file path referenced in the generated report.
This only applies for the 'checkstyle', 'codeclimate',
'sonarqube' and 'gitlab_codeclimate' formats and is
useful when running Hadolint with Docker to set the
correct file path.
--no-fail Don't exit with a failure status code when any rule
is violated
--no-color Don't colorize output
-V,--verbose Enables verbose logging of hadolint's output to
stderr
-f,--format ARG The output format for the results [tty | json |
checkstyle | codeclimate | gitlab_codeclimate | gnu |
codacy | sonarqube | sarif] (default: tty)
--error RULECODE Make the rule `RULECODE` have the level `error`
--warning RULECODE Make the rule `RULECODE` have the level `warning`
--info RULECODE Make the rule `RULECODE` have the level `info`
--style RULECODE Make the rule `RULECODE` have the level `style`
--ignore RULECODE A rule to ignore. If present, the ignore list in the
config file is ignored
--trusted-registry REGISTRY (e.g. docker.io)
A docker registry to allow to appear in FROM
instructions
--require-label LABELSCHEMA (e.g. maintainer:text)
The option --require-label=label:format makes
Hadolint check that the label `label` conforms to
format requirement `format`
--strict-labels Do not permit labels other than specified in
`label-schema`
--disable-ignore-pragma Disable inline ignore pragmas `# hadolint
ignore=DLxxxx`
-t,--failure-threshold THRESHOLD
Exit with failure code only when rules with a
severity equal to or above THRESHOLD are violated.
Accepted values: [error | warning | info | style |
ignore | none] (default: info)
Configuration files can be used globally or per project. Hadolint looks for configuration files in the following locations or their platform specific equivalents in this order and uses the first one exclusively:
$PWD/.hadolint.yaml$XDG_CONFIG_HOME/hadolint.yaml$HOME/.config/hadolint.yaml$HOME/.hadolint/hadolint.yaml or $HOME/hadolint/config.yaml$HOME/.hadolint.yaml
In windows, the %LOCALAPPDATA% environment variable is used instead of
XDG_CONFIG_HOME. Config files can have either yaml or yml extensions.
hadolint full yaml config file schema
failure-threshold: string # name of threshold level (error | warning | info | style | ignore | none)
format: string # Output format (tty | json | checkstyle | codeclimate | gitlab_codeclimate | gnu | codacy)
ignored: [string] # list of rules
label-schema: # See Linting Labels below for specific label-schema details
author: string # Your name
contact: string # email address
created: timestamp # rfc3339 datetime
version: string # semver
documentation: string # url
git-revision: string # hash
license: string # spdx
no-color: boolean # true | false
no-fail: boolean # true | false
override:
error: [string] # list of rules
warning: [string] # list of rules
info: [string] # list of rules
style: [string] # list of rules
strict-labels: boolean # true | false
disable-ignore-pragma: boolean # true | false
trustedRegistries: string | [string] # registry or list of registrieshadolint supports specifying the ignored rules using a configuration
file. The configuration file should be in yaml format. This is one
valid configuration file as an example:
ignored:
- DL3000
- SC1010Additionally, hadolint can warn you when images from untrusted
repositories are being used in Dockerfiles, you can append the
trustedRegistries keys to the configuration file, as shown below:
ignored:
- DL3000
- SC1010
trustedRegistries:
- docker.io
- my-company.com:5000
- "*.gcr.io"If you want to override the severity of specific rules, you can do that too:
override:
error:
- DL3001
- DL3002
warning:
- DL3042
- DL3033
info:
- DL3032
style:
- DL3015failure-threshold Exit with failure code only when rules with a
severity above THRESHOLD are violated (Available in v2.6.0+)
failure-threshold: info
override:
warning:
- DL3042
- DL3033
info:
- DL3032Additionally, you can pass a custom configuration file in the command line with
the --config option
hadolint --config /path/to/config.yaml DockerfileTo pass a custom configuration file (using relative or absolute path) to a container, use the following command:
docker run --rm -i -v /your/path/to/hadolint.yaml:/.config/hadolint.yaml hadolint/hadolint < Dockerfile
# OR
docker run --rm -i -v /your/path/to/hadolint.yaml:/.config/hadolint.yaml ghcr.io/hadolint/hadolint < DockerfileIn addition to config files, Hadolint can be configured with environment variables.
NO_COLOR=1 # Set or unset. See https://no-color.org
HADOLINT_NOFAIL=1 # Truthy value e.g. 1, true or yes
HADOLINT_VERBOSE=1 # Truthy value e.g. 1, true or yes
HADOLINT_FORMAT=json # Output format (tty | json | checkstyle | codeclimate | gitlab_codeclimate | gnu | codacy | sarif )
HADOLINT_FAILURE_THRESHOLD=info # threshold level (error | warning | info | style | ignore | none)
HADOLINT_OVERRIDE_ERROR=DL3010,DL3020 # comma separated list of rule codes
HADOLINT_OVERRIDE_WARNING=DL3010,DL3020 # comma separated list of rule codes
HADOLINT_OVERRIDE_INFO=DL3010,DL3020 # comma separated list of rule codes
HADOLINT_OVERRIDE_STYLE=DL3010,DL3020 # comma separated list of rule codes
HADOLINT_IGNORE=DL3010,DL3020 # comma separated list of rule codes
HADOLINT_STRICT_LABELS=1 # Truthy value e.g. 1, true or yes
HADOLINT_DISABLE_IGNORE_PRAGMA=1 # Truthy value e.g. 1, true or yes
HADOLINT_TRUSTED_REGISTRIES=docker.io # comma separated list of registry urls
HADOLINT_REQUIRE_LABELS=maintainer:text # comma separated list of label schema itemsWhen using base images with non-posix shells as default (e.g. Windows based
images) a special pragma hadolint shell can specify which shell the base image
uses, so that Hadolint can automatically ignore all shell-specific rules.
FROM mcr.microsoft.com/windows/servercore:ltsc2022
# hadolint shell=powershell
RUN Get-Process notepad | Stop-ProcessIt is also possible to ignore rules by adding a special comment directly
above the Dockerfile statement for which you want to make an exception for.
Such comments look like
# hadolint ignore=DL3001,SC1081. For example:
# hadolint ignore=DL3006
FROM ubuntu
# hadolint ignore=DL3003,SC1035 # We accept these issues, because ...
RUN cd /tmp && echo "hello!"The comment "inline ignores" applies only to the statement following it.
Comments are allowed after the ignore=..., you need an extra #
Rules can also be ignored on a per-file basis using the global ignore pragma. It works just like inline ignores, except that it applies to the whole file instead of just the next line.
# hadolint global ignore=DL3003,DL3006,SC1035 # We accept these issues, because ...
FROM ubuntu
RUN cd /tmp && echo "foo"Hadolint is able to check if specific labels are present and conform to a predefined label schema. First, a label schema must be defined either via the command line:
hadolint --require-label author:text --require-label version:semver Dockerfileor via the config file:
label-schema:
author: text
contact: email
created: rfc3339
version: semver
documentation: url
git-revision: hash
license: spdxThe value of a label can be either of text, url, semver, hash or
rfc3339:
| Schema | Description |
|---|---|
| text | Anything |
| rfc3339 | A time, formatted according to RFC 3339 |
| semver | A semantic version |
| url | A URI as described in RFC 3986 |
| hash | Either a short or a long Git hash |
| spdx | An SPDX license identifier |
| An email address conforming to RFC 5322 |
By default, Hadolint ignores any label that is not specified in the label schema. To warn against such additional labels, turn on strict labels, using the command line:
hadolint --strict-labels --require-label version:semver Dockerfileor the config file:
strict-labels: trueWhen strict labels is enabled, but no label schema is specified, hadolint
will warn if any label is present.
It is a common pattern to fill the value of a label not statically, but rather dynamically at build time by using a variable:
FROM debian:buster
ARG VERSION="du-jour"
LABEL version="${VERSION}"To allow this, the label schema must specify text as value for that label:
label-schema:
version: textTo get most of hadolint, it is useful to integrate it as a check in your CI
or into your editor, or as a pre-commit hook, to lint your Dockerfile as you
write it. See our Integration docs.
- Code Review Platform Integrations
- Continuous Integrations
- Editor Integrations
- Version Control Integrations
An incomplete list of implemented rules. Click on the error code to get more detailed information.
-
Rules with the prefix
DLare fromhadolint. Have a look atRules.hsto find the implementation of the rules. -
Rules with the
SCprefix are from ShellCheck (only the most common rules are listed, there are dozens more).
Please create an issue if you have an idea for a good rule.
If you are an experienced Haskeller, we would be very grateful if you would tear our code apart in a review.
To compile, you will need a recent Haskell environment and cabal-install.
-
Clone repository
git clone --recursive git@github.com:hadolint/hadolint.git
-
Install dependencies and compile source
cabal configure cabal update cabal build
-
(Optional) Install Hadolint on your system
cabal install
The easiest way to try out the parser is using the REPL.
# start the repl
cabal repl
# overload strings to be able to use Text
:set -XOverloadedStrings
# import parser library
import Language.Docker
# parse instruction and look at AST representation
parseText "FROM debian:jessie"Compile with unit tests and run them:
cabal configure --enable-tests
cabal build --enable-tests
cabal testRun integration tests:
./integration_test.shDockerfile syntax is fully described in the Dockerfile reference.
Just take a look at Syntax.hs in the language-docker project to see
the AST definition.
Hadolint uses many libraries to do the dirty work. In particular, language-docker is used to parse Dockerfiles and produce an AST which then can be analyzed. To build Hadolint against a custom version of such libraries, do the following. This example uses language-docker, but it would work with any other library as well.
- In the same directory (e.g.
/home/user/repos) clone Hadolint and language-docker git repositories
cd /home/user/repos
git clone https://github.com/hadolint/hadolint.git
git clone https://github.com/hadolint/language-docker.git-
Make your modifications to language-docker
-
In the Hadolint repo, edit the
cabal.projectfile, such that thepackagesproperty points to the other repo too
[...]
packages:
.
../language-docker
[...]- Recompile Hadolint and run the tests
cd /home/user/repos/hadolint
cabal configure --enable-tests
cabal build --enable-tests
cabal test-
replicatedhq/dockerfilelint, the other linter used by the super-linter
-
RedCoolBeans/dockerlint
-
projectatomic/dockerfile_lint

