About ktfmt
This tool uses ktfmt (WASM), the Kotlin formatter created at Meta and built on the Kotlin compiler’s PSI parser plus google-java-format’s layout engine. Unlike ktlint, which reports style violations, ktfmt simply reprints the whole file, so the result does not depend on how the input was laid out. Paste a one-line mess or a nearly tidy file and you get the same answer.
ktfmt also cleans up a few things beyond whitespace. It removes unnecessary semicolons, sorts imports lexicographically, drops imports that are clearly unused, and reflows KDoc comments to the line width. Expressions, names and string templates are never altered.
Both .kt sources and .kts scripts parse, so a build.gradle.kts with plugins { } and dependencies { } blocks is fair game.
Because ktfmt ignores your original line breaks, it is especially good at untangling code that was minified, generated or pasted from a chat window where the newlines were lost. Lambdas, when branches, extension functions and data classes all come back in their idiomatic shapes, and string templates such as "total=$total" are never touched.
The Style option
Style selects one of ktfmt’s three presets:
- ktfmt (Meta) — the default and the style ktfmt is known for.
- Google — the variant used by Google’s Android and Kotlin projects.
- Kotlin coding conventions — the
kotlinlangpreset, which follows the official JetBrains guide most closely and is the usual choice for teams that previously used IntelliJ’s built-in formatter.
The presets differ in details such as where chained calls and trailing lambdas break. Indentation always follows the toolbar here: block indentation uses the indent you pick, and continuation lines (wrapped arguments, chained calls) get twice that amount. The line-width control maps to ktfmt’s maximum width, which is 100 when ktfmt runs on its own; the toolbar opens at 80.
Keyboard: Ctrl/Cmd+Enter formats, Ctrl/Cmd+Shift+C copies, Ctrl/Cmd+K opens the palette. Minify (Ctrl/Cmd+Shift+M) applies to data formats only, not Kotlin.
Gotchas
ktfmt needs input that parses. A missing parenthesis or an unterminated string stops it with a ParseError that includes the line and column, and nothing is reformatted until it is fixed.
Code that relies on a precise manual layout, such as a matrix of numbers or an aligned DSL, will be reflowed. ktfmt has no “ignore” comment, so keep such blocks in a separate file if their shape matters.
Removing unused imports is based on names that appear in the file. In a snippet that uses an extension function or operator imported at the top, ktfmt can occasionally consider the import unused; check imports after formatting partial files. When you only need data classes rather than formatting, the JSON to Kotlin converter generates them from a sample payload.
Examples
Sealed interface and when, Google style
The semicolons between nested classes disappear, a blank line separates members, and each when branch gets a line.
sealed interface Result<out T>{data class Ok<T>(val value:T):Result<T>;data class Err(val message:String):Result<Nothing>}
fun <T> Result<T>.getOrElse(default:T):T=when(this){is Result.Ok->value;is Result.Err->default}sealed interface Result<out T> {
data class Ok<T>(val value: T) : Result<T>
data class Err(val message: String) : Result<Nothing>
}
fun <T> Result<T>.getOrElse(default: T): T =
when (this) {
is Result.Ok -> value
is Result.Err -> default
}
Coroutines chain, Kotlin coding conventions
The trailing lambda stays on the signature line while the call chain wraps with continuation indentation.
suspend fun loadAll(ids:List<String>):List<User> = coroutineScope{ids.map{id->async{api.fetchUser(id)}}.awaitAll().filter{it.active}.sortedBy{it.name}}suspend fun loadAll(ids: List<String>): List<User> = coroutineScope {
ids.map { id -> async { api.fetchUser(id) } }
.awaitAll()
.filter { it.active }
.sortedBy { it.name }
}
Data class and service, default style
ktfmt (Meta) style adds spacing around colons and operators and puts every member of the class on its own line.
data class Item(val sku:String,val qty:Int,val price:Double)
class Cart{private val items=mutableListOf<Item>()
fun add(item:Item){items+=item}
fun total():Double=items.filter{it.qty>0}.sumOf{it.qty*it.price}}data class Item(val sku: String, val qty: Int, val price: Double)
class Cart {
private val items = mutableListOf<Item>()
fun add(item: Item) {
items += item
}
fun total(): Double = items.filter { it.qty > 0 }.sumOf { it.qty * it.price }
}
Common errors and how to fix them
| Error | Cause | Fix |
|---|---|---|
com.facebook.ktfmt.format.ParseError: 1:21: error: Expecting an expression | An assignment, argument or return has nothing after it, often because the paste was cut short. | Complete the expression at the reported line:column, or remove the dangling =. |
com.facebook.ktfmt.format.ParseError: 1:17: error: Expecting ')' | A parameter list or call was opened and not closed. | Add the missing ) before the next { or the end of the line. |
com.facebook.ktfmt.format.ParseError: 1:28: error: Expecting '"' | A string literal is not closed on the same line. | Add the closing quote, or use a raw string (triple quotes) for multi-line text. |
Frequently asked questions
What is the difference between ktfmt and ktlint?
ktfmt rewrites the whole file into one canonical layout. ktlint checks rules and can auto-correct some of them, but leaves most of your own line breaks alone.
Which style matches Android Studio?
Kotlin coding conventions (kotlinlang) is the closest to the official style that Android Studio applies by default. Set the indent to 4 as well.
Can I format build.gradle.kts files?
Yes. Kotlin scripts parse like regular Kotlin, so Gradle Kotlin DSL files format normally.
Why did an import disappear?
ktfmt removes imports it believes are unused. In a partial snippet that may include imports the rest of the project needs, so review them before committing.