# How to Use Kotlin String Templates for Complex Formatting with Multiple Variables and Expressions

> Master Kotlin string templates to format complex strings with variables and expressions. Learn advanced techniques for cleaner, efficient code.

- Repository: [JetBrains/kotlin](https://github.com/jetbrains/kotlin)
- Tags: how-to-guide
- Published: 2026-02-16

---

**Kotlin string templates allow you to embed variables and arbitrary expressions directly inside string literals using `$variable` or `${expression}` syntax, with the compiler automatically optimizing the bytecode to use `StringBuilder` for complex multi-part templates.**

The JetBrains/kotlin repository implements string templates as first-class PSI (Programmatic Structure Interface) elements. When you write a template like `"Hello, $name"`, the compiler represents it as a `KtStringTemplateExpression` containing an ordered list of entry objects that later translate into efficient concatenation operations or `StringBuilder` sequences.

## Understanding the Kotlin String Template Architecture

At the core of every template lies the `KtStringTemplateExpression` class located in [`compiler/psi/psi-api/src/org/jetbrains/kotlin/psi/KtStringTemplateExpression.java`](https://github.com/JetBrains/kotlin/blob/main/compiler/psi/psi-api/src/org/jetbrains/kotlin/psi/KtStringTemplateExpression.java). This PSI node acts as a container for individual template entries, each representing a distinct segment of your string.

The compiler decomposes every template into a sequence of `KtStringTemplateEntry` subclasses:

- **`KtLiteralStringTemplateEntry`** – Represents plain text fragments between interpolations
- **`KtSimpleNameStringTemplateEntry`** – Handles `$variable` syntax for simple identifiers
- **`KtBlockStringTemplateEntry`** – Manages `${expression}` blocks containing arbitrary Kotlin expressions
- **`KtEscapeStringTemplateEntry`** – Processes escaped dollar signs (`$$`) and newline handling

Each entry type serves a specific role in the compilation pipeline, ensuring that the resulting bytecode maintains both correctness and performance.

## Entry Types and Their Use Cases

### Simple Variable Insertion

For direct variable references, use the `$identifier` syntax. This creates a `KtSimpleNameStringTemplateEntry`, which is the most efficient form of interpolation.

```kotlin
val user = "Alice"
val greeting = "Welcome, $user!"  // KtSimpleNameStringTemplateEntry

```

The compiler treats this as a direct reference without additional expression evaluation overhead.

### Expression Blocks

When you need to embed complex logic, method calls, or operators, use the `${expression}` syntax. This generates a `KtBlockStringTemplateEntry` as defined in [`compiler/psi/psi-api/src/org/jetbrains/kotlin/psi/KtBlockStringTemplateEntry.java`](https://github.com/JetBrains/kotlin/blob/main/compiler/psi/psi-api/src/org/jetbrains/kotlin/psi/KtBlockStringTemplateEntry.java).

```kotlin
val score = 95.5
val result = "Final score: ${score.format("%.1f")}%"  // KtBlockStringTemplateEntry

```

The braces ensure the entire expression evaluates as a single unit before string conversion.

### Literal Text and Escaping

Raw text segments become `KtLiteralStringTemplateEntry` instances, while literal dollar signs require `KtEscapeStringTemplateEntry` via the `$$` syntax.

```kotlin
val price = 100
val display = "Price: $$price"  // Outputs: Price: $100

```

In this example, `$$` creates an escape entry emitting a single `$`, while `$price` creates a simple entry for the variable.

## Compiler Optimization and Bytecode Generation

The Kotlin compiler optimizes template compilation through two primary strategies. For short templates with few interpolations, it generates chained `String.plus` calls. For longer or multi-line templates, it automatically switches to `StringBuilder` operations.

The `StringTemplateExpressionManipulator` class in [`compiler/psi/psi-impl/src/org/jetbrains/kotlin/psi/psiUtil/StringTemplateExpressionManipulator.kt`](https://github.com/JetBrains/kotlin/blob/main/compiler/psi/psi-impl/src/org/jetbrains/kotlin/psi/psiUtil/StringTemplateExpressionManipulator.kt) handles the underlying manipulation logic used by the IDE for refactoring and in-place edits. This utility ensures that when you modify templates programmatically, the entry boundaries remain consistent.

You can verify the optimization path by examining the bytecode: templates exceeding approximately ten concatenations trigger the `StringBuilder` path automatically, eliminating manual performance tuning in most cases.

## Best Practices for Complex Kotlin String Templates

**Simple identifiers** – Use `$name` instead of `${name}` when referencing simple variables to avoid unnecessary `KtBlockStringTemplateEntry` overhead.

**Multi-line formatting** – Leverage raw strings (`"""..."""`) combined with `trimMargin()` for readable indentation:

```kotlin
val report = """
    |User: $userName
    |Score: ${score.format("%.2f")}
    |Items: ${items.joinToString(", ")}
    |Cost: $$${price}
""".trimMargin()

```

This pattern handles complex formatting while preserving source code alignment.

**Keyword identifiers** – When interpolating identifiers that match Kotlin keywords or contain special characters, the compiler automatically handles backticks within block entries:

```kotlin
val `if` = "condition"
val text = "Value: ${`if`}"  // Block entry handles backtick-escaped identifiers

```

**Custom interpolation prefixes** – For DSLs requiring literal dollar signs before expressions, use the multi-dollar factory method `createMultiDollarStringTemplate` in [`compiler/psi/psi-api/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt`](https://github.com/JetBrains/kotlin/blob/main/compiler/psi/psi-api/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt) (lines 524-533), which supports `prefixLength` parameters.

## Programmatic Template Creation with KtPsiFactory

When generating code programmatically, use `KtPsiFactory` to construct template PSI nodes. The factory provides three key methods:

- **`createStringTemplate`** – Builds standard double-quoted templates
- **`createRawStringTemplate`** – Creates triple-quoted raw templates
- **`createMultiDollarStringTemplate`** – Generates templates with custom interpolation prefixes for DSL scenarios

Located in [`compiler/psi/psi-api/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt`](https://github.com/JetBrains/kotlin/blob/main/compiler/psi/psi-api/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt) (lines 511-533), these factory methods ensure proper entry ordering and prefix handling when constructing `KtStringTemplateExpression` instances dynamically.

## Common Pitfalls to Avoid

**Unnecessary braces** – Avoid `${variable}` when `$variable` suffices. The simple form generates more efficient PSI structures.

**Raw string escaping** – Remember that `$` remains a template marker even inside `"""..."""`. Use `$$` to emit literal dollar signs in raw strings.

**Nested expressions** – Do not split complex expressions into multiple interpolations. Combine them into a single `${...}` block to ensure atomic evaluation and cleaner bytecode.

**Performance micro-optimization** – Trust the compiler's automatic `StringBuilder` selection. Only manually implement `StringBuilder` chains when profiling reveals bottlenecks in tight loops.

## Summary

- **Kotlin string templates** decompose into `KtStringTemplateEntry` subclasses, with `KtSimpleNameStringTemplateEntry` for variables and `KtBlockStringTemplateEntry` for expressions.
- The compiler automatically optimizes templates to use `StringBuilder` when exceeding simple concatenation thresholds.
- Use `$variable` for simple identifiers and `${expression}` for complex logic or method calls.
- Escape literal dollar signs with `$$`, particularly in raw multi-line strings.
- Generate templates programmatically using `KtPsiFactory` methods like `createStringTemplate` and `createRawStringTemplate`.

## Frequently Asked Questions

### What is the performance cost of using kotlin string templates?

Kotlin string templates compile to the same bytecode as manual `StringBuilder` operations or concatenations. The compiler automatically selects the most efficient strategy based on template complexity, resulting in zero runtime overhead compared to equivalent manual string construction.

### How do I escape dollar signs in raw string templates?

Use the `$$` syntax, which creates a `KtEscapeStringTemplateEntry`. Even inside triple-quoted raw strings (`"""..."""`), single `$` characters trigger template evaluation, making `$$` necessary for emitting literal dollar signs.

### Can I use kotlin string templates with DSLs that require literal dollar signs?

Yes. Use the `createMultiDollarStringTemplate` method from `KtPsiFactory` with a custom `prefixLength` parameter, or manually construct templates using `$$${expression}` patterns where the first `$$` emits a literal `$` followed by the interpolation block.

### When should I use curly braces vs simple $ syntax?

Use simple `$` syntax only for single identifiers without special characters. Use `${}` braces for expressions containing operators, method calls, properties with complex accessors, or identifiers that require backtick escaping. The braces ensure proper expression boundaries and prevent parsing ambiguities.