JAVASCRIPT / STRINGS AND TEMPLATE LITERALS
Replacing text with replace and replaceAll
Replace one or every occurrence of text in a string with replace and replaceAll, handle $ patterns, and compute replacements with a function.
What you will learn
- Choose replace for the first occurrence and replaceAll for all of them.
- Keep the returned string; neither method changes the original.
- Read and escape $ patterns: $& is the match, $1 a group, $$ a literal dollar.
- Use a function replacement to compute per-match text or insert values verbatim.
Understanding Replacing text with replace and replaceAll
Both methods return a brand new string and leave the receiver untouched, because JavaScript strings are immutable and there is no in-place edit to make. The surprise for most people is that `replace` with a string search value only touches the first match: `'2026-09-03'.replace('-', '/')` gives `'2026/09-03'`. That is not an oversight. `replace` was designed around regular expressions, where you ask for every match by adding the `g` flag, and the string form inherited that single-match default.
`replaceAll` arrived in ES2021 to cover the case that had no clean spelling: swap every literal occurrence of a substring. Before it you wrote `replace(/-/g, '/')`, and if the search text came from a variable you first had to build a `RegExp` and escape every metacharacter inside it. With a string search value the match is literal, so `'a.b'.replaceAll('.', '-')` produces `'a-b'` while `'a.b'.replace(/./g, '-')` produces `'---'`.
The second argument has two shapes. A string is a small template: `$&` is the whole match, `$1` and `$2` are numbered capture groups, `$<name>` is a named group, and `$$` is one literal dollar sign. Because that expansion runs over the replacement text, any value that might contain a `$` is unsafe to pass directly; a function replacement, whose return value is inserted verbatim, is the reliable alternative and also hands you the match, the groups, and the offset to compute from.
const line = "cat, cat, dog";
console.log(line.replace("cat", "fox"));
console.log(line.replaceAll("cat", "fox"));
console.log(line.replace(/cat/g, "fox"));
console.log(line);replace and replaceAll build a new string, and the only difference between them is how many matches get consumed: the first one, or all of them.
Worked examples
Function replacement
Computes each replacement from the match and its capture groups instead of using a fixed string.
const csv = "width=12;height=8";
const doubled = csv.replace(/(\w+)=(\d+)/g, (whole, name, value) => `${name}=${Number(value) * 2}`);
console.log(doubled);
const tagged = csv.replace(/\d+/g, (match, offset) => `${match}@${offset}`);
console.log(tagged);Example explained
Line 1The arrow function runs once per match: `whole` is the full match, `name` and `value` are the two capture groups.
Line 2The returned text is inserted literally, so arithmetic like `Number(value) * 2` is possible and no `$` expansion happens.
Line 3The second call has no capture groups, so the parameter after the match is the offset: 6 for "12" and 16 for "8".
Dollar patterns and the global-flag rule
Shows how $&, $1 and $$ are interpreted, and why replaceAll rejects a non-global regex.
const label = "total 40";
console.log(label.replace(/\d+/, "<$&>"));
console.log(label.replace(/(\w+) (\d+)/, "$2 $1"));
console.log("50% off".replaceAll("%", "$$"));
try {
label.replaceAll(/\d/, "#");
} catch (err) {
console.log(err.name);
}Example explained
Line 1`$&` stands for the text that matched, so the digits are wrapped rather than discarded.
Line 2`$1` and `$2` refer to capture groups by position, which is how you reorder the parts of a match.
Line 3`$$` is the escape for a single literal dollar sign, needed whenever the replacement itself contains `$`.
Line 4`replaceAll` throws a TypeError on `/\d/` because a regex without `g` matches once, contradicting "replace all".
When the replacement text is data
Demonstrates that $ expansion applies even with a string search value, and how a function avoids it.
const template = "Hello NAME, meet NAME";
const name = "$& the great";
console.log(template.replaceAll("NAME", name));
console.log(template.replaceAll("NAME", () => name));Example explained
Line 1Dollar patterns are expanded even though the search value is the plain string "NAME", not a regex.
Line 2So `$&` inside `name` expands to the matched text "NAME", and the placeholder survives the replacement.
Line 3Wrapping the value in a function skips expansion completely, because a function's return value is inserted verbatim.
Important notes
A non-global regex works with replace but throws a TypeError with replaceAll, so /x/ and /x/g are not interchangeable across the two methods.
replaceAll is ES2021; in older runtimes use replace with a global regex, and escape regex metacharacters if the pattern comes from a variable.
Common mistakes
Calling s.replace('a', 'b') and then reading s, which still holds the old text because the returned string was discarded.
Using replace('-', ' ') on '2026-09-03' and getting '2026 09-03'; only the first hyphen changes, and the bug stays hidden until a second match exists.
Passing user-supplied text as the replacement, so a stray $& or $1 in it gets expanded and the output silently gains or loses characters.
Try it yourself
Change, predict, then run
In a browser console, set const path = 'src/lib/util.js', then produce 'src.lib.util.js' with one call and 'src/lib/util.ts' with another, and log path afterwards to confirm it is unchanged.
Open the JavaScript workspaceCheck your understanding
Given const s = "a-b-c", which pair of calls produces the same result as each other?
- s.replace("-", "+") and s.replaceAll("-", "+")
- s.replace(/-/g, "+") and s.replaceAll("-", "+")
- s.replace(/-/, "+") and s.replaceAll(/-/, "+")
- s.replaceAll("-", "+") and s.replace(/-/, "+")
Show answer
The g flag makes replace scan the whole string, so /-/g and the string form of replaceAll both yield "a+b+c". Option 3 looks like a matching pair, but s.replaceAll(/-/, "+") never returns anything: replaceAll throws a TypeError when given a regex without the g flag.