Lookahead and lookbehind — collectively, lookarounds — are zero-width assertions: they match a position in the input rather than consuming characters. That definition is technically correct and operationally vague. The reason they earn their place in a regex toolkit is that they let you express constraints on the surrounding context without dragging that context into the match itself. This guide walks the four forms with examples that show up in real codebases, and is honest about when a plain capture group is the better tool.
1. The four lookaround forms
JavaScript's regex engine supports all four forms since ECMAScript 2018:
(?!...) — negative lookahead
(?<=...) — positive lookbehind
(?<!...) — negative lookbehind
They consume zero characters: after the assertion succeeds or fails, the engine's cursor stays where it was. This is what people mean by "zero-width" — it is the same property that makes ^, $, and \b useful.
2. Positive lookahead: matching X only when followed by Y
The classic case is matching a number that is followed by a unit, without consuming the unit. Suppose you want to find file sizes in "MB" but not in "GB":
Run against "Disk: 250 MB free, 4 GB total", this matches just 250. The unit is checked but not captured, which means a single replacement like .replace(/\d+(?=\s*MB\b)/g, "[size]") rewrites the number without touching the unit text. A regular capture group can do the same job, but you would have to reconstruct "MB" in the replacement string. Lookahead is cleaner when the trailing context is awkward to retype.
3. Negative lookahead: matching X only when NOT followed by Y
Negative lookahead earns its keep in password validation and in finding tokens that must not appear in certain contexts. A pragmatic password rule — at least eight characters, including at least one digit and one letter — is usually written as a chain of negative-success lookaheads anchored at the start:
Each lookahead independently asserts "somewhere ahead there is a character matching this class". The order does not affect correctness because each assertion runs from the same anchor. This is also the canonical pattern that makes regex feel powerful and slightly dangerous: every assertion runs once on every position the regex tries, so deeply nested versions can be slow on long inputs.
4. Lookbehind: matching X only when preceded by Y (or not)
Lookbehind is the form that arrived last in JavaScript. ECMAScript 2018 specified both fixed and variable-length lookbehind, and V8 shipped the full version immediately. JavaScriptCore (Safari) was a laggard; full support landed in Safari 16.4 in March 2023. In 2026 you can use it freely on evergreen targets, but if you ship to enterprise users on iOS 15 you still need to feature-detect.
A common case is replacing a number only when it is not preceded by a currency symbol:
Run against "Total $42 plus 10 items", this matches the bare 10 but skips 42. The same logic without lookbehind requires a capture group for the lead character and a more contorted replacement, which is exactly the kind of code that creates bugs on the next iteration.
5. Splitting that keeps the delimiter
Lookarounds are how you split a string while keeping the delimiter as part of one of the resulting pieces. This is a constant requirement when chunking text by sentence terminators, by camelCase boundaries, or by markdown headings:
"FooBarBaz".split(/(?=[A-Z])/)
// "Hi! How are you?" -> ["Hi!", "How are you?"]
"Hi! How are you?".split(/(?<=[.!?])\s+/)
The first uses lookahead to split before a capital letter without consuming it. The second uses lookbehind so the punctuation stays attached to the preceding sentence. Without lookarounds, you would have to capture the delimiter and post-process the split result.
6. Performance: where lookarounds get expensive
JavaScript's regex engine, like PCRE and most engines you encounter outside Go and ripgrep, is a backtracking engine. Lookarounds are not inherently slow, but they multiply the cost of each position the engine examines. Three patterns invite trouble:
- Anchored chains of lookaheads with overlapping classes — for example three lookaheads each containing
.*— run the inner.*repeatedly per position. - Variable-length lookbehind on adversarial input can compound with outer backtracking. Constrain the inner pattern to a known maximum length when you can.
- Anything operating on attacker-controlled input. ReDoS (regular-expression denial of service) is real; the OWASP page on it lists fixes that mostly amount to "use a non-backtracking engine or bound your input length".
For regex that runs server-side on user input, RE2 (linear-time, no backtracking) is the safe choice. For client-side validation in the browser, the native engine is fine — just bound input length.
7. When a capture group is the right answer
Reach for a capture group when you need to extract a substring or refer back to it. Reach for a lookaround when the surrounding context must influence whether the match happens at all but must not be part of the match. The two concrete tells: if you ever find yourself stripping a character off the end of match[0], you wanted a lookahead. If you copy the same literal text into both the regex and the replacement string just to put it back, you wanted a lookbehind or lookahead.
Test your regex live
DevToolNow's Regex Tester runs your patterns against test input in the browser, with match highlighting, group capture, and flag toggles. Useful for prototyping lookarounds without leaving the page.
Open Regex Tester →Frequently asked questions
Q. Are lookahead and lookbehind supported in JavaScript in 2026?
A. Yes — both have been part of ECMAScript since the 2018 edition. V8 (Chrome, Node.js, Edge), JavaScriptCore (Safari 16.4+), and SpiderMonkey (Firefox 78+) all ship lookbehind. If you need to target browsers older than Safari 16.4 you still need to feature-detect or transpile, but for any evergreen environment you can use them freely.
Q. Why does my lookbehind work in Node but not in Safari 14?
A. Variable-length lookbehind (lookbehind with a quantifier inside it) is allowed in JavaScript and most engines accept it, but Safari versions before 16.4 only fully supported fixed-width lookbehind. If you must support older Safari, restrict your lookbehinds to a fixed length or rewrite using capture groups.
Q. Is lookahead expensive at runtime?
A. A simple lookahead like (?=\d) is roughly free — the engine peeks at the next position. The danger is nested or unbounded lookarounds combined with backtracking, which can produce catastrophic backtracking on adversarial input. If a regex is hot-path or runs on user-supplied data, benchmark it on a long mismatching string and consider switching to a non-backtracking engine like RE2.
Q. When should I use a capture group instead of a lookaround?
A. When you only need to extract or replace a substring, a capture group is simpler and faster. Use lookarounds when the surrounding context must match but must not be consumed — for example, splitting on a delimiter while keeping it, or asserting that a number is not preceded by a currency symbol. If you find yourself using a lookahead just to avoid writing the matched text twice, a capture group is usually the better choice.
Q. Do lookarounds work in grep, sed, and awk?
A. Standard POSIX BRE and ERE do not support lookarounds. GNU grep with -P enables PCRE which does, and so do ripgrep (-P), Perl, Python re, .NET, and Java. Standard sed and awk do not. If portability across Unix tools matters, write the regex without lookarounds even if it is uglier — or pipe through a PCRE-aware tool deliberately.
References
- ECMAScript 2018 (ES9) — RegExp Lookbehind Assertions proposal
- MDN Web Docs — Regular expression syntax cheatsheet and Assertions
- regex101.com — interactive engine testbed (PCRE, ECMAScript, Python, Go)
- OWASP — Regular expression Denial of Service (ReDoS)
- Russ Cox — Regular Expression Matching Can Be Simple And Fast (RE2 background)
Note: Browser support facts in this guide reflect ECMAScript 2018 and shipping versions of V8, JavaScriptCore, and SpiderMonkey as of 2026-04. Confirm against caniuse.com or MDN for your specific target matrix before deploying.
About the DevToolNow Editorial Team
DevToolNow's editorial team is made up of working software developers who use these tools every day. Every guide is reviewed against primary sources — IETF RFCs, W3C/WHATWG specifications, MDN Web Docs, and project repositories on GitHub — before publication. We update articles when standards change so the guidance stays current.
Sources we cite: IETF RFCs · MDN Web Docs · WHATWG · ECMAScript spec · Official project READMEs on GitHub