Lesson 4 of 6

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.

← Back to
Next →