chrome-extension://regex-tester-pro · live preview

Pattern

/(\d+)/g

Test string

Build 42 shipped on day 4 of week 18.

flags: g · 3 matches · 0.4 ms

All matching happens in your browser. Patterns and test strings never leave the tab.

Regex Guide

Regex test() vs match() vs exec(): Which JavaScript Method to Use

Updated May 2026 8 min read By the Regex Tester Pro team

Quick answer

Use test() when you only need a yes/no answer. Use match() when you want one match or all matches as an array. Use matchAll() when you want every match with its capture groups. Use exec() when you want to iterate matches statefully (rare, but useful for streaming over very long inputs).

JavaScript has four regex methods that look interchangeable in tutorials but behave very differently in production. The choice changes correctness, performance, and whether your global flag corrupts state across calls. Here is the practical mapping.

JavaScript
// All four methods on the same input
const re = /(\d+)/g;
const text = 'Build 42 shipped on day 4 of week 18.';

// 1. test() returns a boolean
re.test(text);                              // true (and advances lastIndex!)

// 2. match() returns array of matches (no groups when /g)
text.match(/(\d+)/g);                       // ['42', '4', '18']

// 3. matchAll() returns iterator with full groups
[...text.matchAll(/(\d+)/g)];               // [['42', '42', ...], ...]

// 4. exec() returns one match per call, advances lastIndex
let m, hits = [];
const re2 = /(\d+)/g;
while ((m = re2.exec(text)) !== null) hits.push(m[0]);
// hits = ['42', '4', '18']

test(): the boolean check

RegExp.prototype.test(str) returns true if the pattern matches anywhere in the string, false otherwise. It is the right choice when you only care about presence, not the matched text.

The trap: when the regex has the global flag, test() mutates the regex object. Specifically, it sets lastIndex to the position after the last match. Calling test() twice in a row on the same regex with /g can return different results.

Workaround: do not give test() the g flag unless you specifically want stateful behavior. For a yes/no check, the literal /foo/ is correct and side-effect-free.

match(): the simple extraction

String.prototype.match(regex) behavior depends on the global flag:

This asymmetry is the most common source of "where did my groups go?" bugs. If you want all matches with their groups intact, use matchAll(), not match() with /g.

matchAll(): the right answer for "all matches with groups"

String.prototype.matchAll(regex) requires a global regex (/g flag is mandatory) and returns an iterator. Each iteration yields a full match array with groups, exactly like match() without /g.

Spread it into an array if you want random access: [...str.matchAll(re)]. Iterate it directly for streaming over a long input. The iterator is lazy, so you can break early without paying for the rest.

Available since Chrome 73, Firefox 67, Safari 13. If you support anything older, the exec() loop below is the fallback.

exec(): the stateful iterator

RegExp.prototype.exec(str) returns one match per call when used with the global flag. lastIndex on the regex object tracks where the next call will resume. Calling in a loop until null walks every match, just like matchAll().

The reason exec() still exists: it is the only way to interleave processing between matches. If you need to look at match N before deciding whether to look at match N+1 (early-exit, transformation, branching) exec() in a loop is more natural than turning matchAll() into a generator and consuming it manually.

Without the global flag, exec() returns the first match and ignores lastIndex. Calling it repeatedly returns the same first match forever.

Performance: the differences are real but small

For most real workloads (under 10,000 matches per call) the difference between methods is rounding error compared to the regex engine itself. The numbers, on V8, on a typical pattern:

The real performance question is whether the regex itself is well-formed. A bad pattern (catastrophic backtracking) is millions of times slower than any method choice.

Decision flowchart

Walk through it the next time you need a regex method:

  1. Do you only need yes/no? Use test(). Drop the global flag.
  2. Do you need just the first match? Use match() without /g.
  3. Do you need all matches without groups? Use match() with /g.
  4. Do you need all matches with groups? Use matchAll() with /g.
  5. Do you need to interleave logic between matches? Use exec() with /g in a loop.

That covers 99% of cases. If you find yourself reaching for String.prototype.split() or replace() with a regex, those are valid too, just for different goals (tokenizing, transforming).

Try every method side by side

Regex Tester Pro gives you live matching, named groups, replacements, and reference cheatsheets in one Chrome popup. Free, private, no signup.

Add to Chrome, free

Frequently asked questions

Why does my test() return false the second time?
You used the g flag. test() and exec() advance lastIndex on every call when the regex is global. Drop g for boolean checks, or reset lastIndex = 0 between calls.
Can match() with /g return capture groups?
No. That is the historical wart of the API. Use matchAll() instead, which returns the full match array with groups.
Is matchAll() supported everywhere?
In every modern browser since 2019. If you target older browsers, use the exec() loop pattern.
Do I need to reset lastIndex manually?
Only if you are reusing the same regex object across separate iterations. Inline literals (/foo/g inside the call) start fresh each time.
Which method does Regex Tester Pro use?
matchAll() under the hood, so the highlighted matches always carry their group information for the inspector pane.

More by Peak Productivity

Free developer tools, made for the browser

Privacy-first utilities that run locally. No upload, no signup, no watermark.