How can we prepend strings with StringBuilder?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Java's StringBuilder does not have a prepend method. The standard solution is insert(0, value), which shifts existing content to the right and places the new value at position zero. This works correctly for occasional front insertions, but repeated prepends in a loop carry an O(n) cost per call because the internal character array must be shifted each time.
This article covers the basic pattern, the performance characteristics, alternative data structures for prepend-heavy workloads, and the capacity management details that affect both approaches.
Basic Prepend with insert(0, ...)
insert(int offset, ...) is the overloaded method that handles front insertion. Index 0 means "before the first character."
The method returns the same StringBuilder instance, so you can chain calls if you want (though chaining inserts at position 0 can be confusing to read).
Supported Overloads
Like append, insert is overloaded for many types. You do not need to convert values to strings before inserting.
| Overload | Parameter Type | Example |
insert(0, String) | String | sb.insert(0, "prefix") |
insert(0, char) | char | sb.insert(0, '>') |
insert(0, int) | int | sb.insert(0, 42) |
insert(0, long) | long | sb.insert(0, 100L) |
insert(0, double) | double | sb.insert(0, 3.14) |
insert(0, boolean) | boolean | sb.insert(0, true) |
insert(0, char[]) | char[] | sb.insert(0, charArray) |
insert(0, CharSequence) | CharSequence | sb.insert(0, otherBuilder) |
insert(0, Object) | Object (calls toString) | sb.insert(0, myObject) |
Why Prepending is Slower than Appending
StringBuilder stores characters in a backing char[] (or byte[] in compact strings on JDK 9+). Appending writes to the end, which is O(1) amortized because the array grows when needed but existing characters stay put. Prepending forces every existing character to shift right by the length of the inserted content.
For a single prepend on a builder of length n, the cost is O(n) because all n characters must move. If you prepend k times in a loop, the total cost is O(k * n_avg), which can approach O(k^2) for large sequences.
On typical hardware, the prepend version runs 100x to 1000x slower than the append version at 100K iterations. The difference is negligible for small counts (under a few hundred), but it matters for algorithmic string construction.
Alternative: Collect in a Deque, Then Build
If your algorithm naturally produces content front-to-back, the cleanest workaround is to collect parts in a Deque (double-ended queue) and build the final string in one pass.
addFirst on ArrayDeque is O(1) amortized. The final append loop is O(total_length). This avoids the quadratic shifting cost entirely.
Alternative: Append in Reverse, Then Reverse
When you are building a string character by character in reverse order (common in number-to-string conversions or stack-based algorithms), append each character and reverse the result.
This pattern works only when reversing the entire sequence produces the correct result. It is safe for character-by-character construction but breaks for multi-character chunks that have their own internal order.
Alternative: Use String.join or StringJoiner
For cases where you are assembling parts with a delimiter, String.join or StringJoiner is more readable than manual insertion.
These utilities handle the delimiter logic and produce a single string without any intermediate shifting.
Capacity Management
Pre-allocating capacity reduces buffer resizing but does not eliminate the O(n) shifting cost of insert(0, ...).
Capacity is relevant when you know the final string length approximately. It prevents the internal array from growing multiple times during construction. But capacity planning and the shifting cost are independent concerns. Addressing one does not fix the other.
| Concern | Affected By Capacity | Affected By Insert Position |
| Array reallocation | Yes | No |
| Character shifting | No | Yes |
| Final string correctness | No | No |
StringBuilder vs. StringBuffer
StringBuffer has the same API, including insert(0, ...), but is synchronized. In single-threaded contexts (which is almost always the case for string building), StringBuilder is the correct choice because synchronization adds overhead without benefit.
Common Pitfalls
Searching for a prepend method that does not exist. StringBuilder has append and insert, not prepend. The method you want is insert(0, value).
Assuming prepending is as cheap as appending. Appending is O(1) amortized. Prepending is O(n) per call because existing characters shift. This matters in loops.
Using insert(0, ...) inside a large loop without considering alternatives. For hundreds or thousands of prepends, a Deque plus a single append pass is dramatically faster.
Treating reverse() as a universal workaround. Reversing works for character-level construction but corrupts multi-character chunks. Use it only when you are certain the reversal produces valid output.
Forgetting that insert returns the same StringBuilder. Chaining is possible but can reduce readability, especially with multiple positional inserts.
Summary
- Prepend with
StringBuilderby callinginsert(0, value). insertsupports strings, primitives, char arrays, and objects, not justString.- Occasional prepends are perfectly fine. Repeated prepends in loops have O(n) per-call cost and can become quadratic.
- For prepend-heavy workloads, collect parts in an
ArrayDequewithaddFirstand build the final string in oneappendpass. - Pre-allocating capacity reduces buffer resizing but does not affect the shifting cost of front insertions.
- Choose the approach based on actual workload:
insert(0, ...)for simplicity,Dequefor performance.

