String.prototype.matchAll() returns an iterator of every regex match, including capturing groups (same API as MDN String.prototype.matchAll()). Learn the required g flag, how it beats global match() for groups, how it replaces exec() loops, lastIndex safety, five examples, and try-it labs.
01
Kind
Instance method
02
Returns
Iterator
03
Requires
g flag
04
Groups
Kept for every match
05
Mutates?
No (clones regex)
06
Baseline
Widely available
Fundamentals
Introduction
match() with the g flag gives you every full match as plain strings — but it drops capturing groups. When you need groups for every hit, use matchAll().
It returns an iterator (not an array). Use for...of, spread ([...]), or Array.from() to consume it. Each yielded value looks like RegExp.prototype.exec(): full match, groups, index, and input.
💡
Beginner tip
The regex must include g, or you get a TypeError. No matches? You get an empty iterator — not null.
Under the hood, str.matchAll(regexp) validates that a RegExp is global, then calls its Symbol.matchAll method (implemented by RegExp.prototype[Symbol.matchAll]).
Requires the g flag on a real RegExp.
Yields one exec()-shaped array per match (groups included).
Iterator is not restartable — call matchAll() again to rescan.
Clones the regex, so your lastIndex is left alone.
Foundation
📝 Syntax
General form of String.prototype.matchAll:
JavaScript
str.matchAll(regexp)
Parameters
regexp — a RegExp with the g flag, or any object with Symbol.matchAll. Other values become new RegExp(regexp, "g").
Return value
An iterable iterator of match arrays (empty if nothing matches):
matchAll clones the regex, so scanning does not rewrite your lastIndex. Starting at 1 still only yields b and c from that clone’s perspective in this MDN demo.
Example 5 — Named Groups and Empty Results
Collect named captures for every match; empty scans return [].
JavaScript
const text = "fox jumps over the cat";
const re = /(?<animal>fox|cat)/g;
const animals = [...text.matchAll(re)].map((m) => m.groups.animal);
// ["fox", "cat"]
[..."none".matchAll(/xyz/g)]; // [] (empty — not null)
Named groups live on m.groups for each match. Prefer checking array length after spread — do not look for null.
Applications
🚀 Common Use Cases
Parse repeating patterns — IDs, tokens, tags with groups on each hit.
Replace exec loops — cleaner for...of over matches.
Named captures at scale — map m.groups across the string.
Keep lastIndex intact — safe when the same regex is reused elsewhere.
Not for yes/no — use regex.test(str).
Not for full strings only — global match() is simpler then.
🧠 How matchAll() Scans a String
1
Validate / coerce the pattern
Require g on a RegExp, or build new RegExp(value, "g").
Input
2
Clone the regex
Scanning uses a copy so your lastIndex does not change.
Clone
3
Yield each exec()-shaped match
Full match, groups, index, and input for every hit.
Iterate
4
✅
Consume with for...of / spread
Call matchAll again if you need a second pass.
Important
📝 Notes
A RegExp without g throws TypeError.
No matches → empty iterator (not null).
The iterator is not restartable after you finish iterating.
Unlike an exec loop, you cannot steer progress by mutating lastIndex.
Global match() is still fine when you only need full match strings.
Baseline widely available since January 2020.
Compatibility
Browser & Runtime Support
String.prototype.matchAll() is Baseline Widely available — supported across modern browsers since January 2020.
✓ Baseline · Widely available
String.matchAll()
Safe for production when you need every match with capturing groups. Always include the g flag.
ModernWidely available
Google ChromeSupported · Desktop & Mobile
Full support
Mozilla FirefoxSupported · Desktop & Mobile
Full support
Apple SafariSupported · macOS & iOS
Full support
Microsoft EdgeSupported · Chromium
Full support
Internet ExplorerNo native support · Use a polyfill
Polyfill
OperaSupported · Modern versions
Full support
Samsung InternetSupported · Android
Full support
BunSupported · JavaScript runtime
Supported
DenoSupported · JavaScript runtime
Supported
Node.jsSupported · Server runtime
Supported
Android WebViewSupported · Modern WebView
Full support
matchAll()Excellent
Bottom line: Use String.matchAll() for all regex matches with groups. Require g, prefer for...of or Array.from, and remember empty iterators instead of null.
Wrap Up
Conclusion
String.prototype.matchAll() gives you an iterator of every regex match with capturing groups preserved. Use it instead of global match() when groups matter, and instead of exec() loops when you want clearer iteration.
Prefer matchAll when you need groups on every match
Use for...of, spread, or Array.from
Call matchAll again for a second pass
Check for an empty array after spread — not null
❌ Don’t
Omit g (throws TypeError)
Expect groups from global match()
Reuse an exhausted iterator
Assume a miss returns null
Mutate lastIndex to control matchAll progress
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about String.matchAll()
All matches with groups — via an iterator that requires g.
5
Core concepts
📝01
Returns
iterator
API
🎯02
Flag g
required
Regex
📦03
Groups
every match
Capture
❌04
Miss
empty iterator
Bounds
📄05
lastIndex
unchanged
Safe
❓ Frequently Asked Questions
String.prototype.matchAll(regexp) returns an iterator of all matches against a regular expression. Each match is an array shaped like RegExp.prototype.exec() — including capturing groups, index, and input.
If regexp is a RegExp, it must include the global g flag. Otherwise matchAll() throws TypeError. Non-RegExp values are converted with new RegExp(value, "g").
With the g flag, match() returns only full match strings and drops capturing groups. matchAll() yields every match with groups intact. Prefer matchAll when you need groups for every hit.
No. It returns an empty iterator. Spreading or Array.from gives []. That differs from match(), which returns null on a miss.
No. The iterator is not restartable. After a for...of loop finishes, call matchAll() again to get a fresh iterator.
No. It clones the regex internally, so your original regexp.lastIndex stays the same — unlike looping with exec() and g.
Did you know?
Before matchAll, many tutorials taught a while ((match = regex.exec(str)) !== null) loop. That still works, but it mutates lastIndex and is easy to get wrong with shared regexes. matchAll was added to make the “all matches + groups” case safer and clearer.