JavaScript String matchAll() Method

Beginner
⏱️ 11 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
Instance method

What You’ll Learn

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

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.

This page is part of JavaScript String Methods. Related topics include match() and includes().

Understanding the matchAll() Method

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.

📝 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):

SituationReturns / throws
Matches foundIterator yielding exec()-like arrays (groups + index)
No matchesEmpty iterator (→ [] via spread / Array.from)
RegExp without gThrows TypeError
Non-RegExp argumentConverted with new RegExp(value, "g")

Common patterns

JavaScript
const re = /t(e)(st(\d?))/g;
const hits = [..."test1test2".matchAll(re)];
hits[0][0];  // "test1"
hits[0][1];  // "e"
hits[1][0];  // "test2"

// for...of (iterator is exhausted afterward):
for (const m of "table football".matchAll(/foo[a-z]*/g)) {
  console.log(m[0], m.index);
}

// Collect full match strings only:
Array.from("a1b2".matchAll(/(\d)/g), (m) => m[0]);  // ["1", "2"]

⚡ Quick Reference

GoalCode
All matches + groups[...str.matchAll(/pat(g)/g)]
Loop each matchfor (const m of str.matchAll(re))
Map to full stringsArray.from(str.matchAll(re), m => m[0])
Must includeg flag (or TypeError)
No matchesEmpty iterator / []
Full strings onlystr.match(/pat/g) is enough
First match + groupsstr.match(/pat/) (no g)

🔍 At a Glance

Four facts to remember about String.matchAll().

Returns
iterator

Spread to get an array

Flag g
required

Else TypeError

Groups
included

Unlike match + g

lastIndex
unchanged

Regex is cloned

📋 matchAll() vs match() vs exec() loop

matchAll()match() + gexec() + g loop
ResultIterator of match arraysArray of full stringsOne match per exec call
Capturing groupsYes, every matchNo (dropped)Yes
MissEmpty iteratornullFirst exec returns null
lastIndexUnchanged (clone)May update on the regexAdvances as you loop
Best forAll matches + groupsAll full strings onlyLegacy / manual control

Examples Gallery

Examples follow MDN String.matchAll() patterns. Use View Output or Try It Yourself for each case.

📚 Getting Started

See every match with its capturing groups.

Example 1 — Basic matchAll() with Groups

MDN demo: spread the iterator into an array of match results.

JavaScript
const regexp = /t(e)(st(\d?))/g;
const str = "test1test2";

const array = [...str.matchAll(regexp)];

array[0];
// ["test1", "e", "st1", "1", index: 0, input: "test1test2", ...]

array[1];
// ["test2", "e", "st2", "2", index: 5, input: "test1test2", ...]
Try It Yourself

How It Works

Each array element is one match. Index 0 is the full match; later indexes are capturing groups — available for every hit.

Example 2 — for...of Instead of exec()

MDN pattern: walk matches without a while (exec) loop.

JavaScript
const regexp = /foo[a-z]*/g;
const str = "table football, foosball";

for (const match of str.matchAll(regexp)) {
  console.log(
    `Found ${match[0]} start=${match.index} end=${
      match.index + match[0].length
    }.`
  );
}
// Found football start=6 end=14.
// Found foosball start=16 end=24.

Array.from(str.matchAll(regexp), (m) => m[0]);
// ["football", "foosball"]
Try It Yourself

How It Works

After for...of, that iterator is spent. Call matchAll again (as Array.from does here) for a fresh scan.

📈 Practical Patterns

Why groups need matchAll, the g rule, and named captures.

Example 3 — match() Drops Groups; matchAll() Keeps Them

MDN comparison: same regex, different APIs.

JavaScript
const regexp = /t(e)(st(\d?))/g;
const str = "test1test2";

str.match(regexp);
// ["test1", "test2"]  — groups missing!

const array = [...str.matchAll(regexp)];
array[0];  // ["test1", "e", "st1", "1", ...]
array[1];  // ["test2", "e", "st2", "2", ...]
Try It Yourself

How It Works

Global match is fine when you only need the full strings. Reach for matchAll as soon as groups matter for each hit.

Example 4 — Missing g Throws; lastIndex Stays Put

MDN rules: validate the flag, and trust that the regex is not mutated.

JavaScript
try {
  [..."abc".matchAll(/[a-c]/)];  // no g
} catch (e) {
  console.log(e.name);  // TypeError
}

const regexp = /[a-c]/g;
regexp.lastIndex = 1;
const str = "abc";

Array.from(str.matchAll(regexp), (m) => `${regexp.lastIndex} ${m[0]}`);
// ["1 b", "1 c"]  — lastIndex still 1
Try It Yourself

How It Works

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)
Try It Yourself

How It Works

Named groups live on m.groups for each match. Prefer checking array length after spread — do not look for null.

🚀 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.

📝 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.

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.

Modern Widely available
Google Chrome Supported · Desktop & Mobile
Full support
Mozilla Firefox Supported · Desktop & Mobile
Full support
Apple Safari Supported · macOS & iOS
Full support
Microsoft Edge Supported · Chromium
Full support
Internet Explorer No native support · Use a polyfill
Polyfill
Opera Supported · Modern versions
Full support
Samsung Internet Supported · Android
Full support
Bun Supported · JavaScript runtime
Supported
Deno Supported · JavaScript runtime
Supported
Node.js Supported · Server runtime
Supported
Android WebView Supported · 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.

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.

Continue with match(), includes(), or the String methods hub.

💡 Best Practices

✅ Do

  • Always use a regex with the g flag
  • 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

Key Takeaways

Knowledge Unlocked

Five things to remember about String.matchAll()

All matches with groups — via an iterator that requires g.

5
Core concepts
🎯 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.

More String Methods

Return to the hub for slice, trim, replace, and more.

String methods hub →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

8 people found this page helpful