# Kotlin String Concatenation: Efficient and Idiomatic Approaches for Modern JVM Development

> Discover the most efficient and idiomatic ways for Kotlin string concatenation. Learn about string templates, the + operator, and buildString for modern JVM development.

- Repository: [JetBrains/kotlin](https://github.com/jetbrains/kotlin)
- Tags: deep-dive
- Published: 2026-02-18

---

**The most efficient way to perform kotlin string concatenation is using string templates (`"$var"`) or the `+` operator, which the compiler optimizes to `invokedynamic` instructions on JVM 9+ or efficient `StringBuilder` chains on older JVMs, while `buildString` is reserved for complex iterative constructions.**

Modern Kotlin development offers multiple strategies for building strings, but the JetBrains/kotlin compiler automatically selects the optimal bytecode strategy based on your JVM target. Understanding how the compiler transforms your source code ensures you write idiomatic Kotlin without sacrificing performance.

## How the Compiler Optimizes String Concatenation

The Kotlin compiler does not naively translate every `+` operation or template into a new `StringBuilder` instance. Instead, it employs specific IR lowerings and bytecode generators to produce the fastest possible output.

### The FlattenStringConcatenationLowering Pass

In [`compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/FlattenStringConcatenationLowering.kt`](https://github.com/JetBrains/kotlin/blob/main/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/FlattenStringConcatenationLowering.kt), the compiler runs the **FlattenStringConcatenationLowering** transformation. This pass collapses nested `+` operations into a single IR node (`IrStringConcatenation`). 

By flattening the concatenation tree, the backend can emit either an `invokedynamic` call or a compact `StringBuilder` sequence as a single operation, eliminating the intermediate string objects that plague naive concatenation.

### StringConcatGenerator and Bytecode Strategy

The [`compiler/backend/src/org/jetbrains/kotlin/codegen/StringConcatGenerator.kt`](https://github.com/JetBrains/kotlin/blob/main/compiler/backend/src/org/jetbrains/kotlin/codegen/StringConcatGenerator.kt) file implements the actual bytecode generation. For JVM 9+ targets, it generates `invokedynamic` instructions targeting `StringConcatFactory.makeConcatWithConstants`, using placeholder symbols (`\u0001`, `\u0002`) to build a recipe string. 

For JVM 8 and below, it emits a single `StringBuilder` instance with chained `.append()` calls. This dual-path approach ensures optimal performance across JVM versions without requiring source code changes.

## Idiomatic Kotlin String Concatenation Patterns

Choosing the right syntax depends on the complexity of your string construction and whether the structure is known at compile time or runtime.

### String Templates for Simple Interpolation

**String templates** are the default choice for most kotlin string concatenation tasks. They are concise, readable, and receive full compiler optimization.

```kotlin
fun greet(name: String, age: Int): String {
    return "Hello, $name! You are $age years old."
}

```

On JVM 9+, this compiles to an `invokedynamic` call to `makeConcatWithConstants`. On older JVMs, it becomes a single `StringBuilder` chain. The compiler constant-folds literal segments automatically, so never manually concatenate constant strings—the optimizer handles this in `FlattenStringConcatenationLowering`.

### The Plus Operator for Mixed Concatenation

The **`+` operator** receives identical optimization to string templates. When you write `a + b + c`, the flattening lowering treats it the same as `"$a$b$c"`.

```kotlin
fun buildPath(directory: String, filename: String): String {
    return directory + "/" + filename
}

```

This is useful when you need to concatenate existing variables without the syntactic overhead of template braces. However, avoid using `+` inside loops, as the compiler cannot always lift the concatenation out of iterative blocks, potentially creating multiple intermediate objects.

### buildString for Iterative or Conditional Logic

For **large or iterative** concatenations—such as building CSV files, SQL queries, or HTML—use `buildString`. This DSL function creates a single `StringBuilder` instance and provides a receiver scope for appending.

```kotlin
fun toCsv(values: List<String>): String = buildString {
    for ((index, value) in values.withIndex()) {
        if (index > 0) append(',')
        append(value)
    }
}

```

The `buildString` implementation internally uses `StringBuilder().apply { ... }`, ensuring only one object is allocated regardless of loop iterations. This is significantly more efficient than using `+` or templates inside a loop, which would generate a new concatenation operation per iteration.

### Explicit StringBuilder for Advanced Control

When you need to pass the builder reference between functions or inspect intermediate capacity, use an **explicit `StringBuilder`**:

```kotlin
fun generateHtmlTable(rows: List<List<String>>): String {
    val sb = StringBuilder()
    sb.append("<table>")
    for (row in rows) {
        sb.append("<tr>")
        for (cell in row) {
            sb.append("<td>").append(cell).append("</td>")
        }
        sb.append("</tr>")
    }
    sb.append("</table>")
    return sb.toString()
}

```

This pattern is functionally equivalent to `buildString` but offers greater flexibility when you need to manipulate the builder state directly.

## Compiler Configuration Options

While the default behavior is optimal for most cases, the compiler provides flags to force specific concatenation strategies. In [`compiler/arguments/src/org/jetbrains/kotlin/arguments/description/JvmCompilerArguments.kt`](https://github.com/JetBrains/kotlin/blob/main/compiler/arguments/src/org/jetbrains/kotlin/arguments/description/JvmCompilerArguments.kt), the **`-Xstring-concat`** flag allows you to override the backend choice:

```bash

# Force StringBuilder-based concatenation regardless of JVM version

kotlinc -Xstring-concat=inline MyFile.kt

# Force invokedynamic with constants (requires JVM 9+)

kotlinc -Xstring-concat=indy-with-constants MyFile.kt

```

The default mode (`indy-with-constants` on JVM 9+, `inline` otherwise) provides the best performance without manual intervention.

## Summary

- **String templates** (`"$var"`) are the most idiomatic and efficient choice for simple kotlin string concatenation, compiling to `invokedynamic` on modern JVMs.
- The **`+` operator** receives identical compiler optimizations as templates but should be avoided inside loops.
- **`buildString`** is the optimal pattern for iterative or conditional concatenation, using a single `StringBuilder` instance under the hood.
- The compiler's **FlattenStringConcatenationLowering** (in [`FlattenStringConcatenationLowering.kt`](https://github.com/JetBrains/kotlin/blob/main/FlattenStringConcatenationLowering.kt)) and **StringConcatGenerator** (in [`StringConcatGenerator.kt`](https://github.com/JetBrains/kotlin/blob/main/StringConcatGenerator.kt)) automatically flatten chains and select the best bytecode strategy for your JVM target.
- Use **explicit `StringBuilder`** only when you need to reference the builder object across multiple scope boundaries.

## Frequently Asked Questions

### What is the most performant way to concatenate strings in Kotlin?

For simple variable interpolation, string templates and the `+` operator are equally performant because the compiler flattens both into a single `invokedynamic` instruction on JVM 9+ or an optimized `StringBuilder` chain on older versions. For iterative concatenation, `buildString` is most performant as it allocates a single builder regardless of iteration count.

### Does Kotlin compile string concatenation differently than Java?

Yes. While Java traditionally compiles `+` operations to `StringBuilder` chains at the source level, Kotlin's compiler uses the **FlattenStringConcatenationLowering** IR transformation to collapse nested concatenations before bytecode generation. On JVM 9+, Kotlin prefers `StringConcatFactory.makeConcatWithConstants` via `invokedynamic`, whereas older Java compilers do not use this mechanism unless targeting newer JVMs.

### When should I use buildString instead of string templates?

Use `buildString` when constructing strings through loops, multiple conditional branches, or when appending many fragments where the final structure is not known at compile time. String templates are optimized for static structures with interpolated variables, while `buildString` excels at dynamic, procedural string construction.

### Can I force the compiler to use a specific string concatenation method?

Yes. The `-Xstring-concat` compiler flag defined in [`JvmCompilerArguments.kt`](https://github.com/JetBrains/kotlin/blob/main/JvmCompilerArguments.kt) accepts `indy`, `indy-with-constants`, or `inline` values to force `invokedynamic` or `StringBuilder`-based generation respectively. However, the default automatic selection based on JVM target is recommended for production code.