strings.ReplaceAll replaces every non-overlapping occurrence of one literal string with another. There is no regular-expression syntax, callback, or token model involved: matching is based on the exact byte sequence supplied as old.
result := strings.ReplaceAll("api/v1/users", "/v1/", "/v2/")The result is api/v2/users. This small contract makes the function suitable for fixed substitutions where every match receives the same replacement.
Matches do not overlap
The function processes non-overlapping instances. Once an occurrence has been selected, bytes consumed by that match cannot also participate in another match.
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.ReplaceAll("aaaa", "aa", "b"))
}The output is bb, representing two adjacent matches. Replacement text is not fed back into the matching process, so newly emitted text cannot trigger another replacement during the same call.
That detail keeps substitution finite and predictable. Consider replacing a with aa:
expanded := strings.ReplaceAll("cat", "a", "aa")The result is caat. The inserted a bytes are output only; they are not scanned again.
Replacement is literal
Characters that have special roles in regular expressions carry no special meaning here. A period matches a period, an asterisk matches an asterisk, and brackets match their literal byte sequences.
s := strings.ReplaceAll("v1.2.3", ".", "-")
// v1-2-3For fixed text, this avoids the parsing and escaping rules attached to pattern engines. When the target depends on character classes, optional pieces, captures, or other pattern semantics, regexp represents a different operation.
Literal matching also means case is significant. Replacing "go" does not replace "Go". Case folding before substitution can change data beyond the target text, so case-insensitive replacement usually needs an explicit matching strategy rather than an unconditional normalization pass.
Empty old strings have defined behavior
An empty old value is not treated as a no-op. It matches at the start of the string and after each UTF-8 sequence. A source containing k runes therefore has up to k+1 empty matches.
s := strings.ReplaceAll("Go", "", ".")
// .G.o.This behavior can be useful for deliberate insertion, but it is easy to trigger accidentally when the search value comes from configuration or input. Code that intends an empty search value to mean “do nothing” should check that condition before calling the function.
The boundary is based on UTF-8 sequences rather than arbitrary byte positions. For valid UTF-8 text, inserted content appears around decoded character encodings instead of inside their multibyte representation.
The replacement can change byte length freely
old and new do not need equal lengths. Replacement can shrink, expand, or remove matched text.
compact := strings.ReplaceAll("a--b--c", "--", "-")
removed := strings.ReplaceAll("a,b,c", ",", "")The first expression produces a-b-c; the second produces abc. Callers that enforce storage, protocol, or display limits should evaluate the resulting value rather than assuming its byte length remains close to the source.
The function returns a string value. Go strings are immutable from the caller’s perspective, so the source string is not modified in place.
ReplaceAll is equivalent to an unlimited Replace call
The strings package also exposes strings.Replace, which accepts a replacement count. Passing a negative count removes the limit, giving the same replacement scope as ReplaceAll.
a := strings.ReplaceAll(s, old, new)
b := strings.Replace(s, old, new, -1)For code that intends to replace every occurrence, ReplaceAll states that intent directly. Replace remains useful when only the first match or another bounded number of matches should change.
A bounded replacement can matter when repeated delimiters carry distinct roles. Replacing the first separator in a record, for example, is not the same operation as rewriting every separator.
Multiple fixed substitutions need ordering semantics
Several calls can be chained, but each call sees the output of the previous call:
s = strings.ReplaceAll(s, "<", "<")
s = strings.ReplaceAll(s, ">", ">")That sequencing is visible and sometimes desirable. It can also create interactions if one replacement emits text targeted by a later call.
strings.NewReplacer is a separate fit for a fixed set of old/new pairs. Its matching rules consider the configured pairs while scanning the source, rather than repeatedly rescanning a complete intermediate string through a chain of ReplaceAll calls. Choosing between them depends on the intended substitution semantics, not only on the number of pairs.
Byte-oriented matching has Unicode implications
Go strings can hold arbitrary bytes. ReplaceAll searches for the exact string representation of old; it does not perform Unicode normalization or case equivalence.
Two visually similar strings can have different UTF-8 encodings. A precomposed character and a base character followed by a combining mark are distinct byte sequences, so replacing one representation does not automatically replace the other.
That is a useful boundary for protocol fragments, identifiers, delimiters, and other data where exact representation matters. Text systems that require canonical equivalence need a normalization policy outside this function.
The same precision applies to malformed UTF-8. Unlike rune-oriented transformations, literal substring replacement does not require decoding the complete source into Unicode code points. Exact byte sequences can still be matched inside a string that is not valid UTF-8.
Fixed substitution should stay fixed
strings.ReplaceAll is clearest when three conditions hold: the target is literal, every occurrence should change, and every match receives the same output. Moving beyond those conditions usually calls for a different primitive.
A transformation based on individual runes fits strings.Map. Several fixed pairs can fit strings.Replacer. Structural or context-sensitive text needs parsing state, and pattern-based matching belongs to a pattern engine.
Keeping that boundary explicit prevents a simple substitution from quietly becoming a parser. For exact global replacement, strings.ReplaceAll provides a narrow operation whose matching and output rules remain visible at the call site.