Library / SDK
adrienverge/yamllint avatar
adrienverge/yamllint

yamllint: the YAML linter that cares about indentation and line length

A linter for YAML files.

3,475 stars331 forksPythonGPL-3.0

At a glance

What is it?
A small GPL-3.0 Python program that reads a .yml file and complains about duplicated keys, trailing spaces, line length and indentation, with a config format and pre-commit hook that let you tune how strict it gets.
Who is it for?
yamllint is worth adding the moment more than one person edits a YAML file, because the failure it prevents is not a crash but a diff nobody can read. Start with `yamllint .` to see what the default configuration complains about in your own tree before you write a config file, since the rule set is broader than most people expect.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 20 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 9, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Installing the package and pointing it at a directory

yamllint is a single Python program with no runtime dependencies worth naming, and the README's install section is one line:

bash
pip install --user yamllint

The README also notes that yamllint is packaged for all major operating systems and links to installation examples for `dnf` and `apt-get` in the quickstart page of the documentation, which is the place to look if you would rather not install into a Python environment. On Debian and Ubuntu the package name matches the project name, and the project also ships a pre-commit hook configuration, described below.

The everyday usage is four flags, and each one exists for a specific situation:

bash
yamllint my_file.yml my_other_file.yaml ...
yamllint .
yamllint -d relaxed file.yaml
yamllint -f parsable file.yaml

Passing filenames lints those files. Passing a directory recurses into it, which is the form you want in a CI job. `-d relaxed` selects a predefined configuration instead of the default one. `-f parsable` changes the output format to something an editor such as Vim or Emacs can parse for inline diagnostics. A fourth option, `-c /path/to/myconfig`, points at your own configuration file.

The README links to three badges at the top: a CI test status badge running on GitHub Actions against the `master` branch, a Coveralls code coverage badge, and a Read the Docs documentation badge pinned to the latest version. That tells you the default branch is `master`, not `main`, which matters when you write CI configuration.

What the default configuration rejects beyond syntax errors

The one-line description in the repository metadata calls yamllint a linter for YAML files, and the README immediately qualifies that. It does not only check syntax validity, it also checks for weirdnesses such as key repetition and cosmetic problems including line length, trailing spaces and indentation.

Key repetition is the rule that earns the tool its place. YAML itself permits a repeated mapping key, and many parsers accept it silently, taking the last value and throwing the earlier one away. In a CI file that means a stage you thought you had disabled runs anyway. A linter that treats duplication as an error catches a class of bug that a schema validator will not.

The cosmetic rules are where opinions live. Default line length, indentation width and spacing around colons are all enforced unless you change them, and none of those defaults are neutral. This is why the README's own example config starts by turning `line-length` down to a warning and disabling `indentation` entirely, which is a reasonable thing to do for an existing repository that is not going to be reformatted in one commit.

The configuration file is YAML itself, so it looks like this:

yaml
extends: default

rules:
  # 80 chars should be enough, but don't fail if a line is longer
  line-length:
    max: 80
    level: warning

`extends: default` inherits the stock rule set, then individual rules are overridden. Setting `level: warning` keeps the output but stops the command from failing on it, which is the mechanism for gradual adoption.

Disabling checks per line and per block

Some lines cannot obey the rules. A long base64 blob, an embedded certificate, a table of fixed-width output. yamllint handles this with inline comments that disable a check for one line, or for a whole region.

yaml
This line is waaaaaaaaaay too long  # yamllint disable-line

The comment is `# yamllint disable-line` and it applies to the line it sits on. For a region, the block form brackets it with an enable marker:

yaml
# yamllint disable rule:colons
- Lorem       : ipsum
  dolor       : sit amet,
  consectetur : adipiscing elit
# yamllint enable

Note the `rule:colons` part. The disable comment accepts either a bare rule name or a `rule:rule` pair, which is how you suppress one specific rule without suppressing everything in that region. The example above is a deliberately ugly alignment that the colons rule would otherwise reject, and bracketing it is the sanctioned way to keep the alignment that makes a data file readable.

This is a well-designed escape hatch, and it is also the mechanism by which lint coverage decays. A repository full of `disable-line` comments has a linter that reports nothing, so it is worth grepping for those comments periodically rather than assuming the clean run means the rules are satisfied.

Per-rule ignores using gitignore-style patterns

Beyond line-level suppression there is file-level ignoring, and it uses the same pattern syntax as `.gitignore`. That means `*`, `?` and directory patterns behave the way they do in git, which is worth knowing because it is the one piece of yamllint's behaviour inherited from elsewhere rather than invented.

yaml
ignore: |
  *.dont-lint-me.yaml
  /bin/
  !/bin/*.lint-me-anyway.yaml

rules:
  key-duplicates:
    ignore: |
      generated
      *.template.yaml
  trailing-spaces:
    ignore: |
      *.ignore-trailing-spaces.yaml
      /ascii-art/*

The top-level `ignore` key excludes files from every rule, and the leading slash anchors the pattern to the root of the checked directory. The negated pattern re-includes files inside an ignored directory, which is the one piece of gitignore behaviour people rarely expect and need when a build directory holds generated files you still want checked.

The per-rule form is the more interesting half. `key-duplicates` is suppressed for `generated` and `*.template.yaml`, which is the correct call for machine-written files, and `trailing-spaces` is suppressed for `/ascii-art/*`. Both examples point at the same underlying problem: some files cannot satisfy some rules without losing something a human needs, and the fix is to scope the exception to exactly those files rather than to weaken the rule everywhere.

The tradeoff is that a per-rule ignore is invisible in the file it affects. Nothing in the YAML marks it as exempt, so the only record is the configuration file itself.

The pre-commit hook, the test suite and the release cadence

The repository tree shows the infrastructure a maintained Python project tends to have: `.flake8` for the project's own linting, `.pre-commit-hooks.yaml` so the tool can be run as a git hook, `.readthedocs.yaml` for documentation builds, `CHANGELOG.rst`, `CONTRIBUTING.rst`, `docs/`, `tests/` and the `yamllint/` package directory itself.

The `.pre-commit-hooks.yaml` file is the interesting one for adoption. It lets you run yamllint on every commit rather than only in CI, which is the right place to catch a line-length or duplicate-key change because the fix is still small. In practice that means adding the repository as a hook source in a `.pre-commit-config.yaml` and pointing it at the files you care about.

GitHub shows three published releases: v1.38.0 on 2026-01-13, v1.37.1 on 2025-05-04 and v1.37.0 on 2025-03-23. The last push was on 2026-09-19, so the project is currently moving, though the release tags land less often than the commits do. If you pin a version in CI you are pinning roughly eight months behind the working tree.

The licence is GPL version 3, which is unusual for a developer tool compared with the MIT or Apache licences most linters use. In practice the distinction is about how you use it: running `yamllint` as a command in your own CI does not pull GPL obligations into your product, whereas vendoring the source into a codebase would. That is a question for whoever owns the licensing policy at your organisation, and the repository links the full text in `LICENSE`.

What yamllint does not check, and what you add instead

yamllint reads YAML as text with a parser attached. It knows about syntax errors, duplicate keys and formatting, and it does not know what your keys mean. That boundary is the right place to draw the line when you are deciding whether it replaces other tooling.

A schema validator answers a different question: whether a value is the right shape and the right type. A Kubernetes manifest where the replica count is a quoted word rather than a number passes yamllint cleanly. So does a GitHub Actions workflow with a typo in a step name, as long as the YAML parses. yamllint will not catch either.

The comparison that matters most is against editors that already flag YAML problems. A modern editor will underline a syntax error as you type, and several can run yamllint through a language server. What an editor will not give you is a single agreed rule set applied identically on every machine and in CI, which is the entire reason to run the command. The value is consistency, not detection.

The documentation at yamllint.readthedocs.io is where the rule list lives, along with the full quickstart, the custom rule writing guide and the configuration reference. The README links there twice and stops, so if you need to know whether a specific rule is enabled by default you will be reading the docs rather than the repository.

Editorial conclusion

yamllint is worth adding the moment more than one person edits a YAML file, because the failure it prevents is not a crash but a diff nobody can read. Start with `yamllint .` to see what the default configuration complains about in your own tree before you write a config file, since the rule set is broader than most people expect. The `relaxed` profile exists for existing repositories that cannot be reformatted in one commit. Everything about custom rules lives at yamllint.readthedocs.io rather than in the README, and the GPL-3.0 licence matters only if you vendor the code instead of running it as a separate command.

Frequently asked questions

How do I run yamllint on a project?

Install it with `pip install --user yamllint` and then run `yamllint .` to recurse through a directory, or name files directly, for example `yamllint my_file.yml my_other_file.yaml`. Add `-d relaxed` to use the looser predefined configuration, `-c /path/to/myconfig` to use your own, or `-f parsable` for output an editor can consume. Exit status is non-zero when a rule fails at error level, which is what makes it work as a CI step.

How do I stop yamllint complaining about a file or a single line?

Trailing a line with `# yamllint disable-line` suppresses checks on that line only. For a block, open with a comment such as `# yamllint disable rule:colons` and close it with `# yamllint enable`. For files, use the top-level `ignore:` key or a per-rule `ignore:` key, both of which take gitignore-style patterns, which is how a directory of generated files gets exempted from `key-duplicates` only.

Does yamllint check whether my YAML values are correct?

No. yamllint checks syntax and formatting: duplicate keys, line length, trailing spaces, indentation, colons and similar. It has no idea what your keys mean, so `replicas: "three"` passes cleanly. For whether values match a schema, you need a separate validator such as a JSON Schema check, and most projects run both.

Official sources

  1. adrienverge/yamllint on GitHub
  2. Issues
  3. License: GPL-3.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/adrienverge-yamllint.svg)](https://hysenlabs.com/projects/adrienverge-yamllint)