Concepts•Jun 2026•3 min read

String Builder vs String Concatenation

When you're stitching strings together, the choice between a StringBuilder and plain concatenation isn't religion — it's arithmetic. One scales, the other quietly melts your CPU in a loop.

The short answer

String Builder over String Concatenation for most cases. Strings are immutable in C#, Java, JavaScript, and friends.

  • Pick String Builder if joining strings inside any loop, building output of unknown or growing length, or assembling large documents/JSON/SQL where allocation count matters
  • Pick String Concatenation if gluing 2-4 known literals on a single line and readability is the only thing that matters — the compiler optimizes it for you anyway
  • Also consider: The language. Python's f-strings and ''.join(), JS template literals, and C#'s compiler-folded `+` blur the line — the 'builder vs concat' war is sharpest in Java and C# inside loops.

— Nice Pick, opinionated tool recommendations

The verdict

String Builder, and it's not close once a loop is involved. Here's the part people pretend not to understand: in C#, Java, and JavaScript, strings are immutable. a = a + b does not append — it allocates a fresh string the size of both, copies every existing character, then throws the old one away for the garbage collector to mop up. Do that 10,000 times in a loop and you've copied on the order of 50 million characters to build a string that's 10,000 long. That's textbook O(n²), and it's the single most common quiet performance bug I see in junior code. StringBuilder keeps one resizable buffer, appends in place, and materializes the final string exactly once. The whole debate exists only because + reads nicer for two literals. It does. That's where its advantage ends.

Where concatenation is actually fine

I'm decisive, not dishonest: concatenation is the right call for short, fixed, non-looping joins. "Hello, " + name + "!" does not need a builder — reaching for one there is cargo-cult performance theater that makes your code uglier for zero measurable gain. Modern compilers help you here. The C# and Java compilers fold a single-expression chain of + into one optimized call (StringBuilder or an invokedynamic concat) at build time, so the runtime cost of a one-liner is already minimal. The rule is mechanical: count your concatenations and ask if they're in a loop. Fixed count, no loop, two-to-four pieces — use + and move on. The moment the count is dynamic or wrapped in iteration, that comfort evaporates and you switch.

The trap nobody warns juniors about

The killer isn't the obvious result += x — it's the sneaky one hiding behind abstraction. String concatenation inside a recursive call, inside a LINQ/stream Aggregate, inside a logging statement that fires per row, inside a for you didn't recognize as hot. Each looks innocent on the line it lives on, and each is quadratic in aggregate. Profilers will eventually point you here, but by then you've shipped a feature that gets slower the more data your best customers feed it. That's the worst failure mode: it passes every demo and dies in production. StringBuilder removes the footgun entirely — you literally cannot accidentally write the O(n²) version with it. Pre-size the buffer with an initial capacity when you can estimate the length, and you skip the internal doublings too. Defensive by construction beats clever after the profiler.

Language nuance, because it matters

This isn't one war, it's several. In Java and C#, StringBuilder is the canonical answer and the gap is real and large in loops. In Python there is no StringBuilder — the idiomatic, fast pattern is collecting into a list and calling ''.join(parts), which is your builder by another name; CPython sometimes optimizes += on strings, but never rely on an implementation detail. In JavaScript, += on strings is shockingly well-optimized by V8's rope representation, so array-push-then-join only pulls ahead at scale — measure before you 'optimize.' Go has strings.Builder for exactly this reason. The principle survives translation: don't repeatedly allocate-and-copy a growing immutable value. The tool's name changes; the verdict doesn't. Reach for the builder-shaped construct your language ships, and stop hand-rolling quadratic loops.

Quick Comparison

FactorString BuilderString Concatenation
Performance in a loopO(n) — one buffer, appended in place, materialized onceO(n²) — reallocates and copies the whole string every iteration
Memory / GC pressureOne growing buffer; minimal garbage, especially if pre-sizedDiscards an intermediate string per concatenation; heavy GC churn
Readability for short fixed joinsVerbose; .append() noise for what should be one lineClean and obvious: "a" + b + "c"
Risk of accidental quadratic bugEffectively impossible to write the slow versionEasy to hide a quadratic loop behind innocent-looking code
Compiler optimization for one-linersNo help needed — already optimalSingle expressions get folded to one call automatically

The Verdict

Use String Builder if: You are joining strings inside any loop, building output of unknown or growing length, or assembling large documents/JSON/SQL where allocation count matters.

Use String Concatenation if: You are gluing 2-4 known literals on a single line and readability is the only thing that matters — the compiler optimizes it for you anyway.

Consider: The language. Python's f-strings and ''.join(), JS template literals, and C#'s compiler-folded `+` blur the line — the 'builder vs concat' war is sharpest in Java and C# inside loops.

String Builder vs String Concatenation: FAQ

Is String Builder or String Concatenation better?

String Builder is the Nice Pick. Strings are immutable in C#, Java, JavaScript, and friends. Every `+` allocates a brand-new string and copies the whole thing — turn that into a loop and you've built an accidental O(n²) bomb. StringBuilder grows one mutable buffer and copies once. For anything beyond a handful of fixed pieces, StringBuilder wins on memory, GC pressure, and wall-clock time. Concatenation only "wins" on readability for trivial fixed cases — and modern compilers fold those into a single call anyway, so you're not even paying for the prettiness.

When should you use String Builder?

You are joining strings inside any loop, building output of unknown or growing length, or assembling large documents/JSON/SQL where allocation count matters.

When should you use String Concatenation?

You are gluing 2-4 known literals on a single line and readability is the only thing that matters — the compiler optimizes it for you anyway.

What's the main difference between String Builder and String Concatenation?

When you're stitching strings together, the choice between a StringBuilder and plain concatenation isn't religion — it's arithmetic. One scales, the other quietly melts your CPU in a loop.

How do String Builder and String Concatenation compare on performance in a loop?

String Builder: O(n) — one buffer, appended in place, materialized once. String Concatenation: O(n²) — reallocates and copies the whole string every iteration. String Builder wins here.

Are there alternatives to consider beyond String Builder and String Concatenation?

The language. Python's f-strings and ''.join(), JS template literals, and C#'s compiler-folded `+` blur the line — the 'builder vs concat' war is sharpest in Java and C# inside loops.

🧊
The Bottom Line
String Builder wins

Strings are immutable in C#, Java, JavaScript, and friends. Every `+` allocates a brand-new string and copies the whole thing — turn that into a loop and you've built an accidental O(n²) bomb. StringBuilder grows one mutable buffer and copies once. For anything beyond a handful of fixed pieces, StringBuilder wins on memory, GC pressure, and wall-clock time. Concatenation only "wins" on readability for trivial fixed cases — and modern compilers fold those into a single call anyway, so you're not even paying for the prettiness.

Related Comparisons

Disagree? nice@nicepick.dev