Compare trimIndent() and trimMargin(): how does each remove leading whitespace from multi-line strings, and what are the gotchas?
answer
- trimIndent = automatic common-indent removal
- trimMargin = explicit '|' marker (customizable)
- trimIndent uses MINIMUM indent across non-blank lines
- Both drop the blank first/last lines (trimIndent)
- Runtime functions, not compiler magic
basics
~20 sBoth clean up the indentation of multi-line text you wrote inside indented code. trimIndent removes the common leading spaces automatically. trimMargin removes everything up to a marker character you put at the start of each line (default '|').
solid answer
~40 sBoth are String extensions for de-indenting multi-line (usually triple-quoted) literals so source indentation does not leak into the value. trimIndent() finds the minimal common indentation across all non-blank lines and strips it from every line; it also removes the first and last lines if they are blank. trimMargin(marginPrefix = "|") instead trims each line up to and including a margin prefix you place explicitly (the pipe by default), giving you precise control and allowing intentional leading spaces after the marker. Gotchas: trimIndent uses the *minimal* indent, so a single less-indented line reduces the strip amount; blank lines are ignored when computing the indent but the first/last blank lines are dropped. Both are evaluated at runtime (they are normal functions, not compiler magic), and both work with string templates.
code
kotlin · 10 linesfun render(name: String): String = """
|Welcome, $name!
| - Profile
| - Settings
""".trimMargin()
println(render("Sam"))
// Welcome, Sam!
// - Profile
// - Settingsgo deeper
Knows both de-indent multi-line strings and that trimMargin uses a '|' marker.
Explains the minimum-common-indent rule and the first/last blank-line removal, picks the right tool per layout.
Anticipates the misaligned-line gotcha, knows they run at runtime, and uses trimMargin when content needs preserved indentation.
Standardizes multi-line literal style (e.g., always trimIndent for SQL/templates) and reasons about readability/maintainability tradeoffs team-wide.
## The problem they solve A raw multi-line string (triple-quoted `""" ... """`) preserves *all* whitespace exactly, including the indentation you used to keep your source code readable. Without help, the indentation becomes part of the value. ## trimIndent() `fun String.trimIndent(): String` Algorithm: 1. Splits into lines. 2. Ignores **blank** lines when computing indentation. 3. Finds the **minimum** common leading-whitespace prefix of the remaining lines. 4. Removes that many characters from the start of every line. 5. Removes the first and last lines **if they are blank**. ```kotlin val sql = """ SELECT id, name FROM users WHERE active = true """.trimIndent() // "SELECT id, name\nFROM users\nWHERE active = true" ``` **Gotcha — the minimum rule:** if one line is indented less than the others, *less* gets stripped from all of them: ```kotlin val s = """ a b """.trimIndent() // common indent = 6, so " a\nb" ``` ## trimMargin(marginPrefix = "|") `fun String.trimMargin(marginPrefix: String = "|"): String` Each line is trimmed of leading whitespace **up to and including** the first occurrence of `marginPrefix`; the prefix itself is removed. Lines without the marker are left as-is (after the default leading-whitespace handling). This gives explicit control and lets you keep intentional indentation *after* the marker. ```kotlin val menu = """ |Home | Settings |About """.trimMargin() // "Home\n Settings\nAbout" (two spaces before Settings preserved) ``` You can use a custom marker: `text.trimMargin(">")`. ## Choosing between them - **trimIndent** — zero-ceremony; great when indentation is uniform. - **trimMargin** — explicit; use when lines need *different* leading indentation, or when content itself starts with spaces you want to keep. ## Shared facts - Both return a **new** String (immutability). - Both run at **runtime**; they are ordinary stdlib functions, not compile-time transforms. - Both interoperate with `$variable`/`${expr}` templates inside the literal.
- Does trimIndent affect blank lines in the middle of the text?It ignores them when computing the common indent and does not strip content from them, but only the first/last lines are removed if blank; interior blank lines stay.
- How do you keep extra indentation on some lines with trimIndent?You generally can't precisely — trimIndent strips the common minimum. Use trimMargin and put the desired spaces after the marker for explicit control.
trimIndent is autocorrect guessing the margin; trimMargin is you drawing the margin line yourself with a ruler.
saying these in an interview costs you the question
- Believing trimIndent strips a fixed amount rather than the common minimum
- Thinking these are compile-time/zero-cost transformations
- Not knowing the default trimMargin prefix is '|'
- Confusing trim() (whole-string ends) with trimIndent/trimMargin (per-line)