The y flag: sticky matching at lastIndex
The y flag forces a match to begin exactly at lastIndex rather than anywhere at or after it. It either matches at that one position or fails, with no scanning ahead.
At a glance
- Flag letter
- y
- Property
- RegExp.prototype.sticky
- Added in
- ES2015
- Anchors at
- lastIndex, a value you set yourself
- With g also set
- sticky wins, the search never slides forward past a failure
- In this tester
- the tests tab strips y before evaluating a case
In detail
The difference from g fits in one sentence. With g, an attempt that fails at position five slides to position six and tries again; with y, an attempt that fails at position five is the final answer. Sticky turns the regex from a search into a test at a specific offset.
That is exactly the shape a hand written lexer needs. You keep a cursor, assign it to lastIndex, and try each token pattern in turn. Because no pattern can quietly match text further down the input, a token that fails is genuinely absent rather than found somewhere unhelpful, and the loop terminates for the right reason.
Setting both g and y does not give you a lenient global search. Matching /a\d/gy against "a1a2" returns both tokens because they are adjacent, but the same pattern against "1a2" returns nothing at all: the first attempt is at index zero, it fails there, and g does not rescue it. Sticky behaviour takes priority whenever the flag is present.
Sticky is also not the same anchor as ^. The caret anchors to the start of the string, or to a line start with m; y anchors to wherever lastIndex currently points. Combining them gives you a pattern that can only ever match at index zero, which is almost never what the author intended.
Examples
const re = /\d+/y;
re.lastIndex = 0;
re.test("ab12"); // false, position 0 is "a"
re.lastIndex = 2;
re.test("ab12"); // true, matched "12" starting exactly at index 2"a1a2".match(/a\d/gy); // ["a1", "a2"], the tokens are adjacent
"1a2".match(/a\d/gy); // null, the first attempt is at index 0Adding g to a sticky pattern lets it collect consecutive matches. It does not let it skip over anything.
Things that catch people out
- A sticky pattern that fails resets lastIndex to 0, so a tokenizer loop that does not check for the failure restarts from the beginning of the input instead of stopping.
- String.prototype.match with a sticky pattern and no g flag only looks at the current lastIndex, which is 0 on a freshly created literal. It looks like an anchored ^ until you set lastIndex yourself.
- /^\d+/y is not more anchored than /\d+/y. It is less useful, because ^ fails at every position except 0 unless the m flag is also on.
Try it: Regex Tester
Type a pattern and a test string, watch every match highlight as you go, read a plain English breakdown of each token, and check the numbered and named groups it captured.
Regex Tester
LOCAL · Browser-OnlyTest and debug regular expressions with live matching and highlights
Related Regex syntax
All regex syntax →The g flag: global matching and the lastIndex trap
What the g flag changes in a JavaScript regex, why a reused global pattern skips matches through lastIndex, and when matchAll is the safer choice.
The ^ anchor: start of string, or start of line
Where the caret matches with and without the m flag, why it consumes nothing, and the entirely different job it does inside a character class.
The d flag: capture group start and end offsets
What the d flag adds to a match result, how indices.groups mirrors named captures, and when the extra offsets are worth asking the engine for.
\d: the digit class, and the digits it refuses
In JavaScript \d is exactly [0-9], even with the u flag. Here is why other engines disagree and what to use when you need Unicode digits.
\D: everything that is not a digit
\D is the exact complement of \d, which makes it a stripping and splitting tool. It also matches newlines, spaces and every letter in every script.
\w: the word character class, underscore included
\w is exactly [A-Za-z0-9_] in JavaScript. That includes the underscore and excludes every accented letter, which is where most \w bugs come from.
Tools for this
- Regex Tester Free online regex tester - test and debug regular expressions with live matching and highlights
- Regex Playground Regex playground with live match highlighting, named groups, find and replace, and shareable links