JavaScript Regex Flags Explained —g, i, m, s, u, y —When to Use Each
Regex flags are small modifiers that completely change how a pattern behaves.
Forgetting a flag is one of the most common causes of regex bugs in JavaScript. Adding the wrong flag is almost as common.
There are six flags in JavaScript regex:
g —global
i —case-insensitive
m —multiline
s —dotAll
u —Unicode
y —sticky
Each flag exists for a specific reason. Each one changes matching behavior in ways that surprise developers who do not know exactly what they do.
This guide explains every JavaScript regex flag, when to use it, and the bugs that happen when you forget it.
If you want to test flags interactively, the Regex Tester lets you toggle each flag and see the effect immediately.
The g Flag —Global
The global flag makes the regex search for ALL matches, not just the first.
const text = "foo foo foo";
const withoutG = /foo/;
const withG = /foo/g;
console.log(text.match(withoutG)); // ["foo"] —only first match
console.log(text.match(withG)); // ["foo", "foo", "foo"]
Without g, most regex methods stop after finding the first match.
Where g Matters
| Method | Without g | With g |
|---|---|---|
match() | Returns first match with groups | Returns array of all full matches |
exec() | Returns first match repeatedly | Advances lastIndex, returns each match once |
test() | Always true/false | Advances lastIndex |
replace() | Replaces first occurrence | Replaces all occurrences |
matchAll() | Throws TypeError | Works correctly |
The g Flag Trap with test()
const regex = /\d+/g;
console.log(regex.test("abc 123")); // true
console.log(regex.test("abc 123")); // false —lastIndex!
console.log(regex.test("abc 123")); // true
The g flag causes test() and exec() to update regex.lastIndex. This means repeated calls may produce inconsistent results.
Fix: either omit g when using test(), or reset lastIndex.
Related reading: Check Whether a String Matches a Regex in JS —test() vs exec() vs match()
The i Flag —Case-Insensitive
The i flag makes matching ignore case differences.
const regex = /hello/i;
console.log(regex.test("hello")); // true
console.log(regex.test("Hello")); // true
console.log(regex.test("HELLO")); // true
console.log(regex.test("HeLLo")); // true
Without i, "Hello" does NOT match /hello/.
When i Matters
- user input validation
- log parsing (where case varies)
- searching/filtering
- command parsing
function searchCaseInsensitive(text, term) {
const regex = new RegExp(term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "gi");
return text.match(regex);
}
The gi combination (global + case-insensitive) is the most common flag pair.
The m Flag —Multiline
The m flag changes how ^ and $ anchors behave.
Without m:
^matches start of string$matches end of string
With m:
^matches start of each line$matches end of each line
const text = `Line 1
Line 2
Line 3`;
const regex = /^\w+ \d+$/;
console.log(regex.test(text)); // false —^ and $ match entire string
const regexM = /^\w+ \d+$/m;
console.log(regexM.test(text)); // true —matches "Line 1" at line start
Matching Multiple Lines
const text = `ERROR: timeout
INFO: started
ERROR: connection`;
// Without m
const regex = /^ERROR.*/;
console.log(text.match(regex));
// null —^ matches start of entire string, which is "ERROR: timeout" (ok)
// but $ needs multiline for line-by-line
// With m + g
const regexGM = /^ERROR.*/gm;
console.log(text.match(regexGM));
// ["ERROR: timeout", "ERROR: connection"]
The gm combination is essential for line-by-line log parsing.
m Does NOT Affect Dot
A common misconception: m does NOT make . match newlines.
const text = "hello\nworld";
const regex = /hello.world/;
console.log(regex.test(text)); // false —. does not match \n
const regexM = /hello.world/m;
console.log(regexM.test(text)); // still false
For dot to match newlines, you need the s flag.
The s Flag —DotAll
The s flag makes . match newline characters.
const text = "hello\nworld";
const withoutS = /hello.world/;
const withS = /hello.world/s;
console.log(withoutS.test(text)); // false
console.log(withS.test(text)); // true
Without s, . matches everything EXCEPT line terminators (\n, \r, etc.).
When s Matters
- parsing multiline log entries
- extracting content across line breaks
- processing AI-generated responses
- markdown parsing
- HTML extraction
const text = `Error: database
connection failed
at line 42`;
const regex = /Error:.*line \d+/;
console.log(regex.test(text)); // false —.* stops at newline
const regexS = /Error:.*line \d+/s;
console.log(regexS.test(text)); // true
The u Flag —Unicode
The u flag enables proper Unicode handling and Unicode property escapes.
// Without u —\w only matches ASCII
console.log(/^\w+$/.test("こんにち�?)); // false
// With u —still false because \w with u still matches ASCII only
console.log(/^\w+$/u.test("こんにち�?)); // false
// But u enables \p{} property escapes
console.log(/^\p{L}+$/u.test("こんにち�?)); // true
Unicode Property Escapes (Require u)
// Match letters from any script
/\p{L}+/u
// Match emojis
/\p{Emoji}/u
// Match currency symbols
/\p{Sc}/u
// Match punctuation
/\p{P}/u
u Changes How Character Classes Work
With the u flag, character classes handle Unicode code points correctly:
// Without u —matches individual surrogate halves
console.log(/[😀-😎]/.test("\uD83D")); // true (matches surrogate half)
// With u —correctly handles full code points
console.log(/[😀-😎]/u.test("\uD83D")); // false
u Affects \d and \s
With the u flag:
// \d still matches Unicode digits
console.log(/^\d+$/u.test("۱۲۳")); // true
// \s still matches Unicode whitespace
console.log(/^\s+$/u.test("\u00A0")); // true (non-breaking space)
Related reading: \d Is Less Efficient Than [0-9] —Node.js Regex Performance Deep Dive
The y Flag —Sticky
The y flag makes the regex match ONLY at the current lastIndex position.
const regex = /\d+/y;
regex.lastIndex = 4;
const text = "abc 123 def 456";
const match1 = regex.exec(text);
console.log(match1[0]); // "123" —matched at position 4
console.log(regex.lastIndex); // 7
// The next exec starts at position 7
const match2 = regex.exec(text);
console.log(match2); // null —"def" is not digits at position 7
g vs y
The g flag skips non-matching characters to find the next match.
The y flag only matches at the exact current position.
const text = "abc 123 def 456";
// Global —skips "abc " to find "123"
const globalRegex = /\d+/g;
console.log(globalRegex.exec(text)[0]); // "123"
// Sticky —fails because position 0 has "abc", not digits
const stickyRegex = /\d+/y;
console.log(stickyRegex.exec(text)); // null
When y Matters
The sticky flag is useful for tokenizing and lexing:
function* tokenize(text) {
const tokenPatterns = [
/\d+/y,
/[a-z]+/y,
/\s+/y,
/[+\-*/]/y,
];
let pos = 0;
while (pos < text.length) {
for (const pattern of tokenPatterns) {
pattern.lastIndex = pos;
const match = pattern.exec(text);
if (match) {
pos = pattern.lastIndex;
yield match[0];
break;
}
}
}
}
const tokens = [...tokenize("123 + abc - 456")];
console.log(tokens);
// ["123", " ", "+", " ", "abc", " ", "-", " ", "456"]
Flag Order and Syntax
Flags are appended after the closing delimiter:
/pattern/gi // Order does not matter
All these are equivalent:
/pattern/gi
/pattern/ig
pattern.match(/pattern/gi)
new RegExp("pattern", "gi")
Flags Reference Table
| Flag | Name | Effect |
|---|---|---|
g | Global | Find all matches, not just first |
i | Case-Insensitive | Ignore case in matching |
m | Multiline | ^ and $ match line boundaries |
s | DotAll | . matches newline characters |
u | Unicode | Enable Unicode property escapes and strict Unicode handling |
y | Sticky | Match only at lastIndex position |
Common Flag Combinations
// Most common: global + case-insensitive
/pattern/gi
// Log parsing: global + multiline
/^ERROR.*/gm
// Multiline content: global + dotAll
/<div>.*?<\/div>/gs
// Unicode text: global + unicode
/\p{L}+/gu
// Replace all: global + case-insensitive
str.replace(/foo/gi, "bar")
Flag Mistakes That Cause Bugs
Forgetting g with replace()
"foo foo foo".replace(/foo/, "bar");
// "bar foo foo" —only first replaced
Fix: add g.
"foo foo foo".replace(/foo/g, "bar");
// "bar bar bar"
Forgetting m with ^ and $
const lines = "Line 1\nLine 2\nLine 3";
const regex = /^Line \d$/;
console.log(regex.test(lines)); // false
Fix: add m.
Forgetting s for Multiline Content
const text = "<div>\nHello\n</div>";
const regex = /<div>.*<\/div>/;
console.log(regex.test(text)); // false
Fix: add s.
Forgetting u with Emojis
const emoji = "😀";
console.log(/^.$/.test(emoji)); // false —emoji is 2 code units
console.log(/^.$/u.test(emoji)); // true —u treats as single character
FAQ
What are JavaScript regex flags?
Flags are modifiers that change regex matching behavior. The six flags are g, i, m, s, u, and y.
What does the g flag do?
The global flag makes the regex find all matches instead of stopping after the first one.
What does the i flag do?
The case-insensitive flag makes matching ignore letter case.
What does the m flag do?
The multiline flag makes ^ and $ match the start and end of each line, not just the string.
What does the s flag do?
The dotAll flag makes . match newline characters.
What does the u flag do?
The Unicode flag enables Unicode property escapes and correct handling of code points above U+FFFF.
What does the y flag do?
The sticky flag makes the regex match only at the current lastIndex position.
Can I combine regex flags?
Yes. Combine flags like /pattern/gi, /pattern/gms, or any combination.
Final Thoughts
Regex flags are small characters that have enormous impact on matching behavior.
Most regex bugs caused by flags come down to one thing: assuming the default behavior is what you need.
- Default matching stops at the first match —but you usually want
g. - Default matching is case-sensitive —but you often want
i. - Default anchors match string boundaries —but for lines, you need
m. - Default dot excludes newlines —but for multiline content, you need
s. - Default character handling breaks Unicode —for emojis and international text, you need
u. - Default matching skips ahead —for precise positioning, you need
y.
Once you internalize what each flag does, debugging "regex works in Regex101 but not in my code" becomes much faster. Most of the time, the answer is a missing flag.
Related reading: Regex Works in Regex101 but Not in JavaScript —Why
If you want to experiment with flags interactively, the Regex Tester has toggle buttons for every flag, so you can see the effect immediately.
You may also find these related developer tools useful: