CLI tool
ktlint/ktlint avatar
ktlint/ktlint

ktlint: a Kotlin linter and formatter you can run without a config file

An anti-bikeshedding Kotlin linter with built-in formatter

6,747 stars527 forksKotlinMIT

At a glance

What is it?
ktlint is an anti-bikeshedding Kotlin linter with a built-in formatter, MIT licensed, installable via Homebrew or as a native binary or executable JAR. It is opinionated by design, which is exactly where its limits start.
Who is it for?
Adopt ktlint if you want one Kotlin style enforced across a repository with no rule debate and no config file to maintain; install it with brew install ktlint and run ktlint --format once to see the diff size before committing. Skip it if your team needs semantic analysis or type-aware rules, which is detekt's ground, and skip it if you cannot accept a formatter that rewrites files.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Kotlin, according to GitHub's language statistics.

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

Editorial analysis

What ktlint fixes, and the argument it is trying to end

ktlint is a Kotlin linter with a built-in formatter, described in its own README as being in the spirit of standard/standard for JavaScript and gofmt for Go. That comparison is the whole pitch. gofmt does not ask whether you prefer tabs; it decides, and the argument stops. ktlint applies the same posture to Kotlin: the README lists "No configuration required" as the first key feature, ahead of the rule sets and the formatter.

The audience is teams writing Kotlin who are tired of reviewing whitespace, import ordering and line-length diffs. It scans files with the .kt and .kts extensions in the current directory and below, so a single command covers a whole module tree. The project is MIT licensed and the README states it is no longer affiliated with Pinterest and is not affiliated with or endorsed by JetBrains. The last push to the default branch was on 2026-09-17.

The anti-bikeshedding framing is not decoration. Every rule ktlint ships is a decision someone no longer has to make in a pull request, and the cost of that is that the decisions are made for you.

How the pieces fit: CLI, rule engine, ruleset, reporters

The repository layout shows a deliberately split architecture rather than one monolithic binary. ktlint-rule-engine and ktlint-rule-engine-core hold the engine that walks source files and applies rules. ktlint-ruleset-standard holds the rules that ship by default. ktlint-cli is the command line entry point, and a family of reporter modules sits beside it: ktlint-cli-reporter-plain, ktlint-cli-reporter-plain-summary, ktlint-cli-reporter-checkstyle, ktlint-cli-reporter-json, ktlint-cli-reporter-html, ktlint-cli-reporter-sarif, ktlint-cli-reporter-baseline and ktlint-cli-reporter-format.

That split explains two of the README's key features at once. "Several built-in reporters: plain, json, html and checkstyle" is a consequence of those separate modules, and "Allows extension with custom rule sets and reporters" is the reason ktlint-cli-ruleset-core and ktlint-ruleset-template exist. If you want a rule your team cares about that the standard set does not cover, the template module is the starting point rather than a fork of the whole project.

The SARIF reporter is the one worth noting if you already run static analysis in CI, since SARIF is what code scanning dashboards consume. The baseline reporter is the escape hatch: it lets an existing codebase with thousands of violations be brought under ktlint without a single enormous reformat commit. Neither is described in the README beyond the module name and the feature list, so treat the documentation site as the place to confirm how they are invoked.

Installing ktlint and running a first format pass

The README's quick start is two steps. Step one installs with Homebrew:

bash
brew install ktlint

The README points to the documentation site for native executables and the executable JAR under "download and verification", and to "other package managers" for alternatives, so Homebrew is the shortest path rather than the only one. For build integration the README points at "integrations like maven and gradle plugins".

Step two is the first real use. Run it from the root of the Kotlin code you want to check:

bash
ktlint --format
# or
ktlint -F

All files with the .kt and .kts extension in the current directory and below are scanned, and per the README, problems are fixed automatically when possible. The short flag -F is the same operation. If you would rather see the damage before it happens, run ktlint without a flag first: the plain reporter is the default output, and you should expect a list of file paths with rule names and line numbers. On a repository that has never been formatted, that list can be long, which is why the baseline reporter module exists.

One practical note the README does not spell out: --format rewrites files in place, so run it on a clean working tree the first time and read the diff before committing.

The formatter rewrites your files, and the rules are not yours

The obvious failure mode is the one the design invites. ktlint --format edits source files. On a large legacy module the first run can touch nearly every file, which makes the commit unreviewable and pollutes git blame. The baseline reporter exists to soften this, but the README does not document a rollback path, so version control is your undo.

The second limitation is the flip side of "No configuration required". ktlint does support .editorconfig, and that is the documented lever for adjusting behaviour, but the project's identity is that the defaults are correct. A team that wants to negotiate indentation width or import order will find itself fighting the tool's premise rather than configuring it. If your house style diverges from the standard rule set in more than a couple of places, the friction is structural, not incidental.

Third, this is a linter, not a type checker or a semantic analyser. It reads Kotlin source and enforces style and a set of rules; it does not resolve types, follow call graphs or reason about nullability. Rules that need that information are outside what the rule engine modules in this repository are built to do. That is not a defect, but it is the boundary that decides whether ktlint is the right tool for a given check.

Finally, version churn. The most recent release listed is 2.0.0-ALPHA-4 from 2026-08-21, with 1.8.0 from 2025-11-14 as the latest stable-looking line, and 1.7.1 before it. There is a ktlint-com-pinterest-backward-compatibility module in the tree, which suggests the project takes package renames seriously, but pinning a version and reading CHANGELOG.md before upgrading is the only way to know what a bump changes.

ktlint vs detekt, and where ktfmt differs

The comparison people actually search for is ktlint vs detekt, and the split is clean. ktlint is a style linter with a formatter attached: its job is to make the source look a certain way and to fix it. detekt sits on the other side, doing static analysis that looks for code smells, complexity and potential defects, which requires understanding the code rather than its layout. They are complementary. Running both is normal, and the reason is that neither covers the other's ground: ktlint will not tell you a function is too complex, and detekt will not reorder your imports.

Against ktfmt the difference is narrower and more interesting. Both format Kotlin. ktfmt comes from a Google-internal formatter tradition and is, by reputation, even less configurable than ktlint; ktlint's distinguishing feature is that it also carries a rule set beyond formatting, plus the reporter and custom ruleset extension points listed in the README. If all you want is consistent formatting and nothing else, the two are close enough that the deciding factor is which one your build tooling already supports.

Spotless is a third shape entirely: it is a formatter orchestrator that can drive ktlint underneath, so choosing Spotless is not choosing against ktlint. Android lint is a fourth, and it is not really a competitor either, since it targets Android platform correctness rather than Kotlin style.

Maintenance, licence and what an upgrade costs

The repository is not archived and the last push was on 2026-09-17, so the project is receiving commits. That is a statement about the default branch, not a promise about release cadence. The release list shows 1.7.1 in July 2025, 1.8.0 in November 2025, and the 2.0.0 alpha line in August 2026, which is a slow, deliberate rhythm rather than a constant stream.

The upgrade cost is concentrated in two places. Rule sets change between versions, so a version bump can introduce new violations in code that was clean before, and the 2.0.0 alpha line in particular should be treated as a moving target. The module list also shows ktlint-test-ruleset-provider-v3-deprecated, which is the kind of name that tells you an interface has already been superseded; if you write custom rules against ktlint-cli-ruleset-core, expect to track that API across major versions.

On licensing: the README states that all code, unless specified otherwise, is licensed under MIT, with copyright lines for Ktlint, Pinterest, Inc. and Stanley Shyiko. MIT is permissive and places few obligations on how you redistribute or embed the tool. There is also a SIGNING.md and public keys in the repository root, which indicates releases are signed, and a ktlint-bom module for dependency version alignment. None of this is legal advice; if you vendor ktlint into a distributed product, read the LICENSE file rather than this paragraph.

Editorial conclusion

Adopt ktlint if you want one Kotlin style enforced across a repository with no rule debate and no config file to maintain; install it with brew install ktlint and run ktlint --format once to see the diff size before committing. Skip it if your team needs semantic analysis or type-aware rules, which is detekt's ground, and skip it if you cannot accept a formatter that rewrites files. Before rolling it out, check which rule sets the version you pin enables by default and whether the 2.0.0-ALPHA-4 line, released 2026-08-21, is stable enough for your build.

Frequently asked questions

What are the key differences between ktlint and detekt?

ktlint is a Kotlin linter with a built-in formatter, focused on style and on fixing violations automatically. detekt is static analysis aimed at code smells and complexity. The README positions ktlint in the spirit of gofmt and standard/standard, which is a formatting-first posture rather than a defect-detection one.

How do I install ktlint?

The README's quick start installs it with brew install ktlint. It also points to the documentation site for native executables and the executable JAR, to other package managers, and to integrations such as the maven and gradle plugins.

How do I use ktlint to format Kotlin files?

Run ktlint --format, or the short form ktlint -F, from the directory you want to process. The README states that all files with the .kt and .kts extension in the current directory and below are scanned and that problems are fixed automatically when possible.

What is ktlint?

It is an anti-bikeshedding Kotlin linter with a built-in formatter, MIT licensed. The README describes it as a Kotlin linter in the spirit of standard/standard for JavaScript and gofmt for Go, with no configuration required.

How do I set up ktlint in a project?

The README's quick start covers installation and a first run: brew install ktlint, then ktlint --format in the directory you want scanned. For build-level setup it links to integrations for maven and gradle plugins rather than documenting them inline.

How do I add ktlint to Android Studio?

The README does not document an Android Studio plugin. It points to integrations such as the maven and gradle plugins, and the related searches list Ktlint-intellij and Ktlint Android Studio, so the editor integration is not covered by the README.

Official sources

  1. ktlint/ktlint on GitHub
  2. License: MIT
  3. Project website
  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/ktlint-ktlint.svg)](https://hysenlabs.com/projects/ktlint-ktlint)