Groups & Backreferences
So far every pattern has only answered yes/no: does this string match? But often you don't
just want to know whether something matched — you want to pull out the specific piece
that matched. Parentheses () create a capture group, letting you
extract exactly the substring you care about instead of the whole
match.
💡 The Bottom Line
Parentheses (...) both group part of a pattern together and capture
whatever matched inside them, so you can retrieve it separately afterward. Add ?:
right after the opening parenthesis to group without capturing. A backreference like
\1 lets a later part of the pattern require "whatever group 1 already matched,
again" — useful for matching repeated or paired structures.
Capturing pieces of a date
Take a date string like 2026-07-13. Wrapping each piece in parentheses lets you
pull out the year, month, and day separately instead of just confirming the whole thing matched:
const dateRe = /^(\d{4})-(\d{2})-(\d{2})$/;
const match = "2026-07-13".match(dateRe);
match[0] // "2026-07-13" — the whole match
match[1] // "2026" — first group: year
match[2] // "07" — second group: month
match[3] // "13" — third group: day
Groups are numbered left to right by their opening parenthesis, starting at 1 (group 0 is always the whole match, not something you wrote yourself).
Non-capturing groups
Sometimes you want parentheses purely to group part of a pattern — say, to apply a quantifier
to a whole chunk — without cluttering your results with a group you'll never use. Add
?: right after the opening parenthesis:
/(?:ab)+/.test("ababab") // true — "ab" repeated, but nothing gets captured
const re = /(?:https?:\/\/)?(\w+)\.com/;
"visit example.com".match(re)[1] // "example" — only the real capture group shows up
This keeps your captured-groups list focused on the pieces you actually intend to use later.
📋 Capturing vs. non-capturing
(...)— groups and captures the matched text for later use.(?:...)— groups only, for applying a quantifier or alternation to a chunk, without adding an entry to your results.- Use non-capturing groups when you only care about grouping behavior, not the substring itself — it keeps group numbering cleaner in patterns with several groups.
Backreferences: matching something you already matched
A backreference, written \1, \2, and so on, means "match the exact
same text that group 1 (or 2, etc.) already matched here" — not the pattern again, the literal
text. This is how you match paired or repeated structures, like a simple HTML-style tag where the
closing tag must match the opening one:
const tagRe = /<(\w+)>.*?<\/\1>/;
tagRe.test("<b>bold</b>") // true — group 1 captured "b", and \1 requires the closing tag to also be "b"
tagRe.test("<b>bold</i>") // false — closing tag "i" doesn't match what group 1 captured ("b")
Without the backreference, a plain <\w+>.*?<\/\w+> would happily
(and wrongly) match <b>bold</i>, since \w+ on its own
doesn't remember what it matched the first time.
⚠️ Watch Out
A backreference refers to the text a group matched, not the pattern that group was
written with. (\d{3})-\1 requires the exact same three digits to repeat — it does
not mean "three digits, then three (possibly different) digits." That distinction
trips people up the first time they use backreferences.
🙋 There Are No Dumb Questions
Q: Can I name my groups instead of relying on numbers?
A: Yes — most modern regex engines, including JavaScript's, support named groups:
(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}). You then access
match.groups.year instead of match[1], which is much more readable
once a pattern has more than two or three groups.
🔧 Try It Yourself
Using the named-group syntax from the question above, rewrite the date pattern from this
lesson, and confirm "2026-07-13".match(dateRe).groups.month gives you
"07".
✅ Quick Check
What does \1 mean inside a regex pattern?
Next up: lookahead and lookbehind — matching based on what's around a piece of text, without including that surrounding text in the match itself.