September 27, 2026 - 6 MIN READ

Why StringBuilder in 2026?

Immutability, StringBuilder, and the compiler and runtime tricks that make C# strings cheap.

C# / Strings

I have been interviewing engineers for a while now, and one question I ask casually never gets a complete answer:

With all of the ways to build a string in C#, why would someone use StringBuilder in 2026?

Most candidates pause. Some are not even sure what StringBuilder is, and the ones who are, answer it with “concatenation is slow” - which is true, but not the full answer I am looking for.

Advice from the past

One of the first pieces of efficiency advice C# developers were told is to “use StringBuilder to concatenate strings”.

C# String Objects

String objects are immutable: they can’t be changed after they’re created. All of the String methods and C# operators that appear to modify a string actually return the results in a new string object.1

Two consequences the quote leaves out. The == operator on strings compares contents, not references: it is wired straight to String.Equals, which is why s == "done" does what you expect for a reference type.2 And string literals are interned: write the same literal twice and both spots point at one object in the runtime’s intern pool.3

The advice is still valid for loops, because this:

string s = "";
foreach (var line in lines)
{
    // new string object, a full copy of everything so far
    s += line; 
}

allocates and copies the entire accumulated string once per iteration. Double the input and the work goes up roughly four times. Jon Skeet timed it: 100,000 appends took nearly 10 seconds, 200,000 over a minute. A StringBuilder did 1,000,000 in 30 to 40 milliseconds.4

The same loop, with StringBuilder:

var sb = new StringBuilder();
foreach (var line in lines)
{
    // appends into a block of chars;
    // a fresh block links on when it fills
    sb.Append(line);
}
string s = sb.ToString();

One builder, a new block each time it fills, copied once at the end.

A fair benchmark

The memorized answer cannot help here, because the fix depends on the shape of the code, and the rule never named a shape. Michael Shpilt benchmarked both paths and split the test that way.5 In the loop, 1,000 appends repeated 1,000 times:

string += :        313.65934 ms
StringBuilder :      5.53543 ms

More than fifty times faster. That is the textbook case, and it still holds. The docs put the same mechanism in flatter terms:

For routines that perform extensive string manipulation (such as apps that modify a string numerous times in a loop), modifying a string repeatedly can exert a significant performance penalty.6

Now join the same parts in a single expression, no loop, and run it a million times. Same source, second table.5

string +        :     80.22673 ms
interpolation   :     81.42759 ms
StringBuilder   :    237.69841 ms
String.Format   :    260.18319 ms

StringBuilder is one of the slowest choices, almost three times plain concatenation. Reach for it out of habit and you pick near the bottom of the four.

The reason is in the builder’s own design: it holds the text as a chain of blocks and only allocates when there is no room left, sizing each new block by doubling until it hits the 8,000-character cap that keeps them off the large object heap.6 For a single join there is no accumulation left to amortize, so you pay the blocks and the final copy for the privilege of appending things you could have written in one line.

The compiler caught up

Part of the single-expression speed is that interpolation is no longer what people remember it as. Before C# 10 it lowered to String.Format with an object[] and a format string parsed at runtime, which is the source of the “interpolation is slow” belief. The runtime team benchmarked the change with BenchmarkDotNet, formatting four ints into a version string:7

MethodMeanRatioAllocated
String.Format + boxing111.70 ns1.00192 B
C# 10 handler66.75 ns0.6040 B

Forty percent faster and nearly five times less memory. The remaining 40 bytes is the returned string itself; seed the handler with a stackalloc buffer and the run drops to 48.57 nanoseconds.

The lowering is shaped by how many holes the interpolation has. All-constant, it becomes one literal. A few interpolated values, and the compiler emits String.Concat. Only the general, formatted case falls back to String.Format, which is the path nobody wants.8 And it is still improving: interpolating a nullable int came down from 78.12 nanoseconds in .NET 8 to 62.95 in .NET 9.9

StringBuilder has been getting faster from its own side too: appending a constant string went from 7.597 nanoseconds in .NET 7 to 3.756 nanoseconds in .NET 8.10

The extreme case is constants:

string s = "hello" + " " + "there";

Every part is a constant, so the compiler emits the single literal "hello there". There is no runtime concatenation left for StringBuilder to rescue.11

StringBuilder’s strengths

So StringBuilder is for loops, and everything else is interpolation. I guess we are done?

Not quite. There are two real answers, and the second one is the part nobody says out loud. You reach for StringBuilder in 2026 when you are building a buffer piece by piece and you do not know its final length up front, so the builder links on fresh blocks as it grows and the allocations amortize out.6 Or, and this one matters more, when you need to change the middle of it. Watch what the same task costs against an immutable string:

var b = new StringBuilder("hello, world");
b.Replace("world", "bench");      // one pass, in place
b.Insert(0, "draft: ");            // in place

string s = "hello, world";
s = s.Replace("world", "bench");   // a brand-new string, old one abandoned
s = "draft: " + s;                 // another brand-new string

Insert, Replace, Reverse, per-character indexing, and a capacity pinned ahead of time are all things the builder does without rebuilding the whole thing.6 None of them are available on a string at all. Capacity is the one people forget: give the builder its final size up front and it skips the intermediate block allocations.

My verdict

I have changed how I score the question. If the answer that comes back is “concatenation is slow in a loop,” that is correct, but it tells me nothing. A candidate who stops there is quoting a benchmark from the .NET Framework 2.0 era, and I cannot tell whether they understand it or merely remember it.

I want to hear where the rule actually applies. A loop whose length you cannot know in advance, or a buffer you are going to rewrite in the middle. A candidate who cannot name either has memorized a rule. A candidate who knows when to use StringBuilder and when plain concatenation and interpolation beat it, has a tool instead of a reflex.

Footnotes

  1. Microsoft Learn, “C# strings,” immutability of strings. https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/ ↩

  2. Microsoft Learn, “Equality operators,” string equality testing. https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators ↩

  3. Microsoft Learn, “String.Intern method,” the intern pool. https://learn.microsoft.com/en-us/dotnet/api/system.string.intern ↩

  4. Jon Skeet, “Concatenating Strings Efficiently,” timing of loop concatenation. https://jonskeet.uk/csharp/stringbuilder.html ↩

  5. Michael Shpilt, “Challenging the C# StringBuilder,” loop versus single-expression benchmark. https://michaelscodingspot.com/challenging-the-c-stringbuilder/ ↩ ↩2

  6. Microsoft Learn, “StringBuilder class,” capacity expansion when the existing capacity is inadequate. https://learn.microsoft.com/en-us/dotnet/api/system.text.stringbuilder ↩ ↩2 ↩3 ↩4

  7. .NET team, “String interpolation in C# 10 and .NET 6,” interpolated string handler benchmark. https://devblogs.microsoft.com/dotnet/string-interpolation-in-c-10-and-net-6/ ↩

  8. Microsoft Learn, “Interpolated string literals,” compilation of interpolated strings. https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated ↩

  9. .NET team, “Performance improvements in .NET 9,” nullable int interpolation. https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-9/ ↩

  10. .NET team, “Performance improvements in .NET 8,” StringBuilder.Append of a constant. https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/ ↩

  11. Jon Skeet, “Concatenating Strings Efficiently,” compile-time folding of literal concatenation. https://jonskeet.uk/csharp/stringbuilder.html ↩