The Problem with Numbered Groups
Regular capture groups use parentheses and are accessed by index: match[1], match[2]. With five or more groups, knowing which index corresponds to which data requires counting parentheses — a maintenance burden and a frequent source of bugs when the regex is modified.
const dateRegex = /(d{4})-(d{2})-(d{2})/;
const m = "2026-06-13".match(dateRegex);
console.log(m[1]); // year — must remember this is index 1
Named Capture Groups Syntax
Named capture groups use (?<name>...) and populate a groups object on the match result.
const dateRegex = /(?<year>d{4})-(?<month>d{2})-(?<day>d{2})/;
const { year, month, day } = "2026-06-13".match(dateRegex).groups;
// year = "2026", month = "06", day = "13"
Practical Examples
// Parse structured log lines
const logRegex = /(?<ts>S+) (?<level>INFO|WARN|ERROR) (?<msg>.*)/;
const { ts, level, msg } = line.match(logRegex)?.groups ?? {};
// Swap first and last name in a replace
const nameRegex = /(?<first>w+) (?<last>w+)/;
"John Doe".replace(nameRegex, "$<last>, $<first>");
// → "Doe, John"
// With matchAll for multiple matches in a string
const tagRegex = /<(?<tag>w+)>(?<content>[^<]*)</k<tag>>/g;
for (const match of html.matchAll(tagRegex)) {
console.log(match.groups.tag, match.groups.content);
}
Back-References with \k
// \k<name> references a named group in the same pattern
const xmlTag = /<(?<tag>w+)>.*?</k<tag>>/;
xmlTag.test("<div>content</div>"); // true
xmlTag.test("<div>content</span>"); // false
Browser Support
Named capture groups landed in ES2018: Node.js 10+, Chrome 64+, Firefox 78+, Safari 11.1+. Not in Internet Explorer. For IE support, use numbered groups or compile with Babel.