Kotlinter Gradle puts ktlint inside the build, with hooks and per source set tasks
Painless, fast ktlint plugin for Gradle
At a glance
- What is it?
- Kotlinter Gradle is a Gradle plugin that runs the ktlint engine over Kotlin sources through Gradle's incremental build and Worker API. It covers a narrow, well understood job, and its sharpest edges are version pinning, generated source excludes and a pre-push hook that only installs from the root project.
- Who is it for?
- Kotlinter Gradle fits teams already on Gradle 8.4 or newer who want ktlint wired into check, on developer machines and CI, with one plugin block and an .editorconfig. It does not fit projects that cannot move to Gradle 8.4, that are pinned to ktlint below 1.0, or that want lint rules to be owned by a separate build tool.
- Can I use it commercially?
- Yes. Apache-2.0 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 9 days 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 October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A narrow problem: keeping Kotlin source tidy without a separate tool run
Kotlinter Gradle addresses one specific problem: Kotlin code that lives in a Gradle build and drifts out of style because nobody wants to format it by hand. The project describes itself as a painless Gradle plugin for linting and formatting Kotlin source files with the ktlint engine, and it states that it aims to be easy to set up with zero required configuration and to behave the way you would expect out of the box.
The audience is therefore Gradle users who already write Kotlin, whether through the JVM, Multiplatform or Android plugin, and who want the same style rules applied on a laptop and on a CI agent without keeping a separate ktlint binary in the pipeline. There is no standalone CLI of its own, no hosted service, and no homepage beyond the repository. The repository also carries test fixture projects named test-project, test-project-android and test-project-no-kotlin-plugin, which tells you the plugin is expected to behave differently depending on whether a supported Kotlin Gradle plugin is applied.
That last point matters more than it first appears. Kotlinter only auto-registers its tasks when one of the supported Kotlin Gradle plugins is present. In a project without one, the plugin does nothing for you unless you define tasks by hand.
The engine runs inside Gradle, not beside it
The mechanism is worth understanding before you install anything. Kotlinter embeds the ktlint engine directly into Gradle's incremental build rather than shelling out to a downloaded executable, and it uses the Worker API to parallelize lint and format work. The project claims this is the reason it is fast, and the claim is architectural: source change detection is Gradle's, not a separate cache's.
Two task types back this. The documentation lists standalone LintTask and FormatTask types for defining custom tasks, and the source set tasks inherit from Gradle's SourceTask, which is what gives them includes, excludes and source customization. Lint and format runs happen in a worker process, and the JVM arguments for that worker are configurable through workerJvmArgs.
Because the work is a worker process rather than an in-process call, memory is a real knob on large codebases. The documentation also notes a JDK 24+ specific default: workerJvmArgs defaults to --sun-misc-unsafe-memory-access=allow on JDK 24 and newer, which suppresses a sun.misc.Unsafe deprecation warning printed by the Kotlin compiler embedded in ktlint.
Two tasks, and check now depends on lintKotlin
Once a supported Kotlin Gradle plugin is applied, Kotlinter adds formatKotlin, which formats Kotlin source code according to ktlint rules or warns when auto-format is not possible, and lintKotlin, which reports Kotlin lint errors and fails the build by default. The documentation is explicit that check becomes dependent on lintKotlin, so the standard Gradle verification entry point picks up style failures with no further wiring.
Granular tasks are added per source set, named formatKotlin plus the source set name and lintKotlin plus the source set name. In a standard Kotlin project that gives you lintKotlinMain and lintKotlinTest as separate targets, which is what you want when a test source set legitimately uses different conventions from production code.
The build fails on lint errors by default. Formatting is more forgiving: the default configuration sets ignoreFormatFailures to true, so a problem ktlint cannot auto-fix does not by itself break the build. That is a sensible default for a formatting task that also rewrites files, but it is worth knowing that a green build does not guarantee every rule was satisfied.
Installation: one plugin block, then replace the release placeholder
The plugin is published on the Gradle Plugins Portal under the id org.jmailen.kotlinter. The instructions tell you to replace the placeholder in the examples with the current release version or a version you choose.
For a single module in a Kotlin build script:
plugins {
id("org.jmailen.kotlinter") version "<release>"
}For a multi-module or Android build, apply the plugin to the root project with apply false, then apply it in each module that contains Kotlin source. In the root build.gradle.kts:
plugins {
id("org.jmailen.kotlinter") version "<release>" apply false
}and in each module build.gradle.kts:
plugins {
id("org.jmailen.kotlinter")
}Groovy equivalents exist for each of these, using the id "org.jmailen.kotlinter" syntax with the same version placeholder.
After that, run the standard Gradle verification lifecycle and lintKotlin will be part of it. The first thing to look at is the diff produced by formatKotlin on an existing codebase, since a formatting rule set applied to code that was never formatted can produce a large change.
The pre-push hook has one hard requirement: the root project
Kotlinter can install a git hook that runs on pre-push. The install task is named installKotlinterPrePushHook, and the hook runs lintKotlin and, if there are errors, formatKotlin, then exits non-zero, leaving the changed files for you to commit. That sequence is a sensible ordering: it tells you what is wrong, fixes what it can, and still refuses the push.
The constraint is the part to remember. You must apply the Kotlinter plugin to your root project for this task to be available at all. If you use git worktree, you must install the hook from the parent git directory, which is the kind of detail that quietly breaks in a team that has adopted worktrees for parallel branch work.
To have the hook installed automatically whenever someone runs the build, add this to the root project build.gradle.kts:
tasks.check {
dependsOn("installKotlinterPrePushHook")
}The Groovy form uses tasks.named('check') with dependsOn 'installKotlinterPrePushHook'. Note that the hook install is tied to the check lifecycle, so it happens as a side effect of running a build, not as a separate setup step you run once.
Generated sources need an explicit exclude, and the default pattern is wrong for many repos
The granular tasks derive from SourceTask, so includes, excludes and source are all open to you. The documentation calls out a subtlety that trips people up: exclude paths are relative to the package root, not to the project directory. To exclude at the src directory level you need a path check instead of a plain relative path.
The Kotlin example for that is:
tasks.withType<LintTask> {
exclude { it.file.path.contains("/src/generated") }
}
tasks.withType<FormatTask> {
exclude { it.file.path.contains("/src/generated") }
}The Groovy example narrows the same idea to a named task:
tasks.named("lintKotlinMain") {
exclude { it.file.path.contains("/src/generated") }
}This matters for Android and Multiplatform builds, where generated sources exist by default and are not written in your house style. Running a formatter over them either rewrites machine written files or reports failures nobody can fix. The single most common reason a new Kotlinter user sees noise in the first run is missing excludes for generated code.
ktlintVersion is yours to override, and that is also the main compatibility risk
The kotlinter extension carries four documented options. The ktlintVersion property overrides the default ktlint version used by the plugin, and the documentation is candid about it: compatibility will generally be good, but ktlint consumer API changes may break compatibility in some rare cases. The remaining options are ignoreFormatFailures, ignoreLintFailures and reporters, where the reporter choices are checkstyle, html, json, plain and sarif.
The default configuration block looks like this:
kotlinter {
ktlintVersion = "1.5.0"
ignoreFormatFailures = true
ignoreLintFailures = false
reporters = arrayOf("checkstyle")
}The plugin states a compatibility floor of Gradle 8.4 or newer and ktlint 1.0 or newer, and says Kotlin compatibility is generally fine as long as the language features are supported by the version of ktlint selected. That last clause is the one to keep in mind. A project using a very recent Kotlin language feature can be blocked by an older ktlint, and the fix is the version pin rather than a plugin change.
Worker memory is adjustable for the same reason, since ktlint runs out of process:
tasks.withType<ConfigurableKtLintTask> {
workerJvmArgs.add("-Xmx1g")
}On JDK 24 and newer the plugin pre-populates that argument list with --sun-misc-unsafe-memory-access=allow. Use add to keep that default in place, and set if you intend to replace the list entirely.
Apache-2.0, a steady release line, and where to point the linting instead
The project is licensed Apache-2.0. For a build plugin that runs inside a company build, that licence carries no copyleft obligation on your own source, though the specifics of how you distribute a build should be checked with whoever handles licence questions on your side.
On upkeep, the recent releases move steadily: 5.5.0 on 2026-05-17, 5.6.0 on 2026-07-05 and 5.7.0 on 2026-08-09. The last push was on 2026-10-14. The repository is not archived. The documentation for the current line is version 5 and later, with older guidance kept separately in README-4x.md, which is a reasonable sign that major version transitions are documented rather than silently dropped.
The real alternative to consider is not another plugin but another placement for ktlint. Invoking ktlint from a command line or through a generic Gradle Exec task keeps the lint rules outside the build, which is sometimes what you want when the same rules must be shared with an IDE that does not use Gradle, or when the repository is a mix of Gradle and non-Gradle modules. The trade-off is that you give up Gradle's incremental build, the per source set task granularity, and the automatic link to check, and you gain a separate command that every contributor and CI job has to remember. Kotlinter makes the opposite bet, that the build is the only place the rules need to live.
Editorial conclusion
Kotlinter Gradle fits teams already on Gradle 8.4 or newer who want ktlint wired into check, on developer machines and CI, with one plugin block and an .editorconfig. It does not fit projects that cannot move to Gradle 8.4, that are pinned to ktlint below 1.0, or that want lint rules to be owned by a separate build tool. Before adopting it, confirm that your Gradle version satisfies the 8.4+ floor, run one formatKotlin pass on a branch and inspect the diff, then decide whether the ktlintVersion override in the kotlinter extension should stay at the plugin default or be pinned to a version you test against.
Frequently asked questions
How do I set up Kotlinter Gradle in a multi-module Kotlin project?
Apply the plugin to the root project with apply false and the version, then apply it in each module build script without a version. The root project also has to apply the plugin if you want the pre-push hook task to be available.
What Gradle and ktlint versions does Kotlinter Gradle require?
The documented compatibility floor is Gradle 8.4 or newer and ktlint 1.0 or newer. Kotlin support generally depends on the language features being supported by the ktlint version selected, and the ktlintVersion property can override the default.
How do I stop Kotlinter Gradle from linting generated sources?
The source set tasks inherit from SourceTask, so you can exclude by path. Because exclude paths are relative to the package root, the documentation suggests a path check such as exclude { it.file.path.contains("/src/generated") } applied to LintTask and FormatTask.
Official sources
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.
[](https://hysenlabs.com/projects/jeremymailen-kotlinter-gradle)Was this useful?