ktfmt: one Kotlin formatter, two styles, and no options for how it formats
A program that reformats Kotlin source code to comply with the common community standard for Kotlin code conventions.
At a glance
- What is it?
- ktfmt is a Kotlin pretty-printer built on google-java-format, distributed as a standalone jar, a JetBrains plugin, and a set of Gradle and Maven integrations. It offers a Kotlinlang style and a Google style and deliberately leaves almost nothing configurable, on the argument that a single format is worth more than options.
- Who is it for?
- ktfmt fits a Kotlin team that wants one formatting result across every repository and every developer, checked in CI, without a style debate. It is the wrong choice for a team that wants to tune indentation, line width, or trailing commas freely, because the project treats that as a deliberate omission rather than a gap.
- 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 3 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 formatter that refuses to be configurable
ktfmt is a program that pretty-prints, formats, Kotlin code, based on google-java-format. The lineage matters, because it explains the shape of the tool. google-java-format is the Java formatter that ktfmt's design is based on. ktfmt takes that model and applies it to Kotlin.
The design decision is stated in the project summary with unusual force. There is no configurability as to the formatter's algorithm for formatting, apart from the different styles or limited `.editorconfig` support. This is a deliberate design decision to unify our code formatting on a single format.
That is an unusual position for a formatter, and it is the whole argument of the project. The alternative model, where a linter exposes a rule set you configure, pushes the style decision onto every repository, and the result is that two teams using the same tool still produce different code, so a diff between them is noisier than it needs to be. ktfmt removes the knob so that the output is a property of the tool rather than of the configuration.
The consequence is that ktfmt is a formatter rather than a linter. It does not report style problems and it does not have a configurable rule catalogue. It rewrites your file, and what it rewrites it to is the same for everyone.
The other structural fact is that the project is hosted by Kotlin, the organisation, and the project summary carries a Slack badge for the ktfmt channel on the Kotlin Slack, an issues link, and a Maven Central version badge for the artifact coordinates `com.facebook:ktfmt`, which is the last remnant of the project's origin at Facebook.
Two styles, and one flag that changes the indent
The style options are few, and one of them is a single flag.
The command line invocation is:
$ java -jar /path/to/ktfmt-<VERSION>-with-dependencies.jar [--kotlinlang-style | --google-style] [files...]The two styles are the Kotlinlang style and the Google style. The difference is stated as one thing: `--kotlinlang-style` makes ktfmt use a block indent of 4 spaces instead of 2. That is the entire documented difference between the two styles, and it is worth knowing how small it is before you pick one, because a formatter is only worth adopting if you can accept its output wholesale.
The jar is distributed with dependencies in the name, which tells you the packaging decision. There is no separate dependency resolution step, no classpath assembly, and no chance of a version conflict with something else on the machine, which is the property that makes a formatter practical to run in a CI container or a pre-commit hook.
Installation through Homebrew is a single command:
$ brew install ktfmtThe JetBrains route is a plugin from the plugin repository, and the installation is five steps through the IDE's settings and the Marketplace tab. The plugin is disabled by default, which is a sensible default for something that replaces a core IDE action. To enable it in the current project you go to File, then Settings, then ktfmt Settings, or on macOS IntelliJ IDEA, then Preferences, then Editor, then ktfmt Settings, and check the Enable ktfmt checkbox. A notification is presented when you first open a project offering to do this for you. To enable it by default in new projects, the path is File, then New Project Settings, then Preferences for new Projects, then Editor, then ktfmt Settings.
Once enabled it replaces the normal Reformat Code action, which is triggered from the Code menu or with the Ctrl-Alt-L keyboard shortcut by default. That replacement is the point of the plugin: you do not have to remember to run the right formatter, because the IDE's own reformat action is the formatter.
Formatting a range instead of a file
The formatter can act on whole files, on limited lines with `--lines` or `--line`, or on specific offsets with `--offset` and `--length`.
The line range syntax is described precisely. Line ranges look like `5` or `1:12,14`, may be used multiple times, and are 1-based. Offset ranges must provide matching `--offset` and `--length` pairs, and `--length=0` formats the whole line containing the given `--offset`.
That set of rules is what a real code formatter needs and what most people never think about until they hit it. A range covering a single line, a range covering a span with a hole in the middle, a range specified as a byte or character offset rather than a line, and the special case where a zero length means the containing line rather than nothing at all. Each of those has a plausible alternative implementation and a different answer, and the tool has to pick one and document it.
There is an important caveat about what partial formatting does and does not do. Partial formatting limits the core pretty-print replacements to the selected ranges, but whole-file cleanup passes, such as import cleanup and multiline string formatting, still run afterward, to match google-java-format's cleanup-after-selection behavior.
That behaviour is inherited from google-java-format, and it is the kind of thing that surprises people. You ask for one line to be reformatted and you get that line reformatted plus the imports reordered and the multiline strings normalised. The reason is that the cleanup passes are not range-local, so restricting them would leave the file inconsistent. The consequence is that in a CI check, a range format can still fail on a file whose imports were never in range, which is a behaviour worth knowing before you wire it into a commit hook that only formats the staged lines.
EditorConfig support is four properties, not a style guide
There is a flag called `--enable-editorconfig`, and it is worth being precise about what it does, because the name overpromises.
It makes ktfmt enable limited support to override the style's configuration based on the following subset of editorconfig properties. The list is four: `max_line_length` overrides the max line width, `indent_size`, or `tab_width` if `indent_size = tab`, overrides the block indent, `ij_continuation_indent_size` overrides the continuation indent, and `ktfmt_trailing_comma_management_strategy`, one of `none`, `only_add` or `complete`, overrides the trailing comma management strategy.
Four properties, and one of them is not a standard EditorConfig property at all. `ktfmt_trailing_comma_management_strategy` is a ktfmt-specific key, which is a small sign that the tool has a slightly awkward relationship with the EditorConfig standard. It works, but the standard is being used as a container for tool-specific settings rather than as a shared vocabulary.
Note what is not on the list. There is no way to configure the algorithm, which is the point of the project, and there is no knob for things like brace placement beyond what the two styles already decide.
The IntelliJ integration has a related mechanism with a different name. To configure IntelliJ to approximate ktfmt's formatting rules during code editing, you can edit your project's `.editorconfig` file to include the Kotlin section from one of the files inside the `docs/editorconfig` directory in the repository. So the IDE uses an EditorConfig file as the vehicle, and the tool itself reads `.editorconfig` only when you pass the flag. Two different mechanisms, one shared file.
There is one more IntelliJ-specific detail. In order to share the settings, make sure to commit the file `.idea/ktfmt.xml` into your codebase. That is a small but real deployment step, since it means the plugin's settings live in version control and travel with the project.
Line breaks inside lambdas are yours to keep
The most recent behavioural addition in the project summary is about preserving lambda line breaks, and it is the rule that distinguishes ktfmt from a formatter that would flatten your DSLs.
By default, ktfmt respects user-authored line breaks inside lambda bodies. The stated purpose is that this is useful for DSLs where nesting carries semantic meaning, Jetpack Compose UI hierarchies and Kotlin Gradle scripts being the named examples, without ktfmt prescribing a specific outcome.
The rule has two halves, and the example in the project summary shows both:
// Multi-line in source is preserved
App {
SelectableCard {
Button { Text("Click me") }
}
}
// Single-line in source is also preserved
dependencies { implementation(libs.androidx.activity) }
val state = remember { mutableStateOf(false) }A lambda body whose source spans multiple lines stays multi-line, and one that fits on a single line stays single-line if written that way. The formatter is not deciding the shape of your lambda at all in this case.
This matters more than it might look. In a Compose hierarchy, the line breaks in the source are the structure a reader navigates by, and a formatter that collapses them produces a wall of nested braces that is technically identical and much harder to read. In a Gradle script, the block shape of a dependency declaration carries the grouping. Preserving the author's choice is the difference between a formatter that can be applied to an existing codebase and one that has to be argued about.
It is also a deliberate narrowing of the formatter's remit, and it is consistent with the rest of the project. The tool decides layout, the author decides structure, and the two do not overlap.
The ecosystem around the formatter is where most of the work happens
Almost nothing in the README is about the formatting algorithm, and most of it is about how you run the tool in a real repository.
There is a Gradle plugin, ktfmt-gradle, available on the Gradle Plugin Portal, with setup instructions in its own how-to-use section. Alternatively you can use Spotless with the ktfmt Gradle plugin, and for Maven the advice is to consider Spotless with the ktfmt Maven plugin. Spotless reaches ktfmt through its ktfmt Gradle and Maven plugins.
There is a pre-commit hook, listed under the language-formatter hooks, which is the route that puts the formatter in front of a developer rather than in CI.
The IntelliJ plugin is the other half, and the two together are the arrangement most teams end up with: the IDE formats as you type so the diff is already clean, and a commit hook or a build check catches the rest.
The repository layout explains the rest of the project. There is a `core/` directory for the formatter itself, a `ktfmt_idea_plugin/` directory for the IDE plugin, a `playground/` directory, an `artifacts/` directory, a `docs/` directory holding the images used in the comparison table and the editorconfig files, and a `buildSrc/` directory with the build logic. The build is Gradle with a Kotlin DSL, `build.gradle.kts` and `settings.gradle.kts`, plus a `gradlew` wrapper.
The comparison table in the project summary is worth reading as a positioning statement. It shows the same code before formatting, after ktfmt, after ktlint, and after IntelliJ, which is an implicit argument that ktfmt's output is distinct from both of the alternatives rather than a subset of either.
The release history shows steady work: v0.63 in May 2026, v0.64 in June 2026, and v0.65 in October 2026, with the last push on 2026-10-07. The version number being still zero means the project does not claim a stable format, which is a reasonable position for a tool whose output people commit to their repositories.
Editorial conclusion
ktfmt fits a Kotlin team that wants one formatting result across every repository and every developer, checked in CI, without a style debate. It is the wrong choice for a team that wants to tune indentation, line width, or trailing commas freely, because the project treats that as a deliberate omission rather than a gap. Check three things before you adopt it: that your runtime is JDK 11 or newer, since that is the stated minimum, that the two available styles match your existing code, because a formatter that reformats a whole codebase is a large diff, and that you read the note about there being no configurability of the formatting algorithm itself, which is the decision that will shape your experience of the tool.
Frequently asked questions
How do I install and run ktfmt from the command line?
Download the formatter jar from the releases and run it as `java -jar /path/to/ktfmt-<VERSION>-with-dependencies.jar [--kotlinlang-style | --google-style] [files...]`, or install it with `brew install ktfmt`. The minimum supported runtime version is JDK 11.
What is the difference between the ktfmt Kotlinlang style and Google style?
One thing. `--kotlinlang-style` makes ktfmt use a block indent of 4 spaces instead of 2. The project also states there is no configurability as to the formatter's algorithm for formatting apart from the different styles and limited editorconfig support, which is a deliberate decision to unify code formatting on a single format.
Can ktfmt format only part of a file?
Yes. It can act on limited lines with `--lines` or `--line`, or on specific offsets with `--offset` and `--length`. Line ranges look like `5` or `1:12,14`, may be used multiple times, and are 1-based, and offset ranges must provide matching `--offset` and `--length` pairs, where `--length=0` formats the whole line containing the given offset.
Does ktfmt support EditorConfig?
Only with the `--enable-editorconfig` flag, and only for a limited subset: `max_line_length`, `indent_size` or `tab_width` when indent_size is tab, `ij_continuation_indent_size`, and the ktfmt-specific `ktfmt_trailing_comma_management_strategy`. When reading from stdin, pass `--stdin-name=<path>` to resolve EditorConfig settings as if the input were at that path.
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/kotlin-ktfmt)Was this useful?