JavaScript Regex Flags Explained: g, i, m, s, u, y, d
June 9, 2026 · 4 min read
JavaScript has seven regex flags. Most developers know g and i, but the newer flags (s, u, y, d) are less understood — and they solve real problems. This guide explains all seven with clear examples.
How flags work
Flags are added after the closing slash of a regex literal, or as the second argument to new RegExp():
const re1 = /pattern/gi; // literal — g + i flags
const re2 = new RegExp("pattern", "gi"); // constructor form
You can check which flags are active via re.flags (returns a sorted string like "gi").
g — global
The g flag makes the regex find all matches instead of stopping at the first.
"aaa".match(/a/) // → ["a"] — one match
"aaa".match(/a/g) // → ["a","a","a"] — all matches
Without g, match() returns the first match plus capture groups. With g, it returns a flat array of all matched substrings (no capture group info). Use matchAll() with g to get an iterator of full match objects:
const re = /(\w+)@(\w+)/g;
for (const m of "a@b c@d".matchAll(re)) {
console.log(m[1], m[2]); // "a" "b", then "c" "d"
}
Gotcha: Stateful regexes. A regex object with g tracks lastIndex. Calling exec() repeatedly advances through the string. Reset lastIndex to 0 if you reuse the same regex object on different strings.
i — case-insensitive
Makes character matching ignore case differences:
/hello/i.test("HELLO") // true
/[a-z]/i.test("Z") // true — range expanded to both cases
Affects character classes and literals, but not backreferences:
/(a)\1/i.test("Aa") // false — backreference must match the actual captured text
m — multiline
Changes ^ and $ anchors to match at the start/end of each line rather than the entire string:
const text = "line1\nline2\nline3";
text.match(/^\w+/gm) // → ["line1", "line2", "line3"]
text.match(/^\w+/g) // → ["line1"] — without m, ^ only matches start-of-string
The m flag does not make . match newlines — that's what s does.
s — dotAll (ES2018)
By default, . matches any character except \n, \r,
, and
. The s flag removes that exception:
/foo.bar/.test("foo\nbar") // false
/foo.bar/s.test("foo\nbar") // true
This is especially useful when matching multi-line blocks like HTML tags or JSON fragments:
const html = "<div>\n content\n</div>";
html.match(/<div>(.*?)<\/div>/s)?.[1].trim() // "content"
u — unicode (ES2015)
Enables full Unicode mode. Affects:
- Surrogate pairs — without
u, a regex operates on 16-bit code units;\u{1F600}(emoji) is treated as two separate characters. Withu, it's treated as one:
/^.$/u.test("😀") // true — one emoji = one character
/^.$/.test("😀") // false — two UTF-16 code units
\p{...}Unicode property escapes — only work withu:
/\p{Emoji}/u.test("😀") // true
/\p{Script=Arabic}/u.test("مرحبا") // true
- Strict mode — invalid escape sequences throw instead of being silently ignored.
Use u any time you're working with multilingual text, emoji, or Unicode ranges.
y — sticky (ES2015)
The y flag works like g but requires the match to start exactly at lastIndex — it doesn't scan forward:
const re = /\d+/y;
re.lastIndex = 4;
re.exec("abc 123") // → ["123"] — match starts at index 4
re.exec("abc 123") // → null — lastIndex is now 7, no match there
Sticky is useful for building hand-written tokenizers and parsers where you advance through a string position by position and want guaranteed sequential matching.
d — indices (ES2022)
Adds a indices property to match results, giving you the start and end positions of each capture group:
const m = "2026-06-09".match(/(\d{4})-(\d{2})-(\d{2})/d);
m.indices[0] // [0, 10] — full match
m.indices[1] // [0, 4] — year
m.indices[2] // [5, 7] — month
m.indices[3] // [8, 10] — day
Before d, you had to compute positions manually. It's now available in Chrome 90+, Safari 16+, Firefox 131+, and Node 16+.
Combining flags
Flags can be combined freely:
/pattern/gim // global, case-insensitive, multiline
/pattern/gsu // global, dotAll, unicode
The only incompatible pair is u and v (the newer verbose Unicode flag) — they can't be used together.
Quick reference
| Flag | Name | What it does |
|---|---|---|
g |
global | Find all matches, not just the first |
i |
case-insensitive | Ignore case when matching |
m |
multiline | ^/$ match start/end of each line |
s |
dotAll | . matches newlines |
u |
unicode | Full Unicode mode + \p{} |
y |
sticky | Match only at lastIndex, no scanning |
d |
indices | Add indices array to match results |
Test flags interactively
The Regex Tester lets you toggle any combination of flags and see all matches highlighted in real-time — including the substitution and unit-test tabs for verifying your patterns against expected inputs.