The (?!...) syntax is a negative lookahead assertion. It lets you match text only when it is not followed by a specific pattern—without consuming the characters you peek at. It is zero-width, powerful for exclusions, and a stepping stone into advanced regex.
01
(?!...)
Not followed by
02
Zero-width
Peek, don’t eat
03
Assertion
Not + or *
04
Exclude
Filter suffixes
05
vs (?=)
Positive twin
06
Validation
Password rules
Fundamentals
Introduction
Sometimes you need to match part of a string while rejecting certain what-comes-next situations. For example, match foo but not when it is immediately followed by bar. You could try long alternation lists, but negative lookahead expresses the rule directly: /foo(?!bar)/.
Old tutorials often call (?!...) a “quantifier,” but that name is misleading. Quantifiers like + and * repeat tokens. Lookahead is an assertion: a condition on upcoming text that does not become part of the final match. Think of it as peeking ahead and saying “only continue if the next characters are not what I forbid.”
Concept
Understanding (?!...) Negative Lookahead
Syntax: (?!pattern) where pattern is any valid regex sub-expression. When the engine reaches this point, it checks whether the text starting at the current position matches pattern. If it does, the assertion fails; if it does not, the assertion succeeds and matching continues.
In "foobar", foo is followed by bar, so (?!bar) fails. In "foobaz", the next characters are baz, not bar, so the match succeeds and returns only "foo"—the lookahead text is not included.
💡
Beginner Tip
Read (?!bar) aloud as “not followed by bar.” The matched result never includes the lookahead portion—only the part before it.
Usage
How to Use Negative Lookahead
Place (?!...) immediately after the text you want to conditionally match, or at the start of a pattern to reject entire strings:
JavaScript
/foo(?!bar)/; // foo not followed by bar
/\d+(?! dollars)/g; // numbers not followed by " dollars"
/^(?!.*password).{8,}$/i; // 8+ chars, no "password"
new RegExp("foo(?!bar)"); // constructor form
"http://a.com".match(/http(?!s)/); // ["http"] — not https
Combine with the global flag when you need every qualifying match in a string. Use anchors (^, $) inside lookaheads for whole-string validation rules.
Foundation
📝 Syntax
JavaScript
(?!pattern) // negative lookahead — must NOT follow
(?=pattern) // positive lookahead — MUST follow (contrast)
(?!foo|bar) // not followed by foo OR bar
^(?!.*badword).+$ // whole string must not contain badword
token(?!suffix) // token only when suffix absent
Common patterns
/foo(?!bar)/ — match foo unless bar follows.
/http(?!s)/ — match http but not https.
/\d+(?! dollars)/g — numbers not immediately followed by dollars.
/^(?!.*@spam\.com$).+@.+/ — emails not from blocked domain.
Cheat Sheet
⚡ Quick Reference
Goal
Pattern / API
Not followed by text
/part(?!bad)/
Exclude https
/http(?!s)/
Exclude suffix globally
/\d+(?! dollars)/g
Reject forbidden substring
/^(?!.*word).+$/
Positive counterpart
(?=pattern)
Constructor form
new RegExp("a(?!b)")
Does not consume input
Zero-width — not in match result
Compare
📋 Negative vs Positive Lookahead
(?!...) forbids what follows; (?=...) requires it.
Negative
(?!bar)
Must NOT be followed by bar
Positive
(?=bar)
MUST be followed by bar
On "foobaz"
/foo(?!bar)/
Matches foo
On "foobar"
/foo(?!bar)/
No match — bar follows
Hands-On
Examples Gallery
Open DevTools Console (F12) or use Try-it links. Examples cover basic exclusion, number filtering, password rules, domain blocking, and side-by-side comparison with plain matching.
📚 Getting Started
Match text only when a forbidden suffix is absent.
After matching foo, the engine peeks ahead. If bar is next, the assertion fails and the match is rejected. The returned match is only foo, never the lookahead text.
📈 Practical Patterns
Filtering, validation, and real-world exclusions.
Example 2 — Match http But Not https
Distinguish insecure URLs from secure ones with /http(?!s)/.
After matching http, the engine checks whether s comes next. For https, the assertion fails, so the pattern does not match. For plain http, there is no trailing s, so the match succeeds.
Example 3 — Reject Passwords Containing password
Use a start-of-string lookahead to forbid a substring anywhere in the value.
JavaScript
const rule = /^(?!.*password).{8,}$/i;
console.log(rule.test("MySecret1!")); // true
console.log(rule.test("short")); // false — too short
console.log(rule.test("myPassword123")); // false — contains "password"
^(?!.*password) checks from the start that nowhere in the string does password appear. Then .{8,}$ enforces minimum length. This pattern validates the whole input, not just a substring.
Example 4 — Block Emails from a Domain
Accept email-shaped strings except those ending in @spam.com.
The negative lookahead at the start rejects any string containing @spam.com at the end. The rest of the pattern checks a simplified email shape. Real email validation needs more rules, but the lookahead cleanly expresses the exclusion.
Example 5 — With vs Without Negative Lookahead
See how adding (?! dollars) changes which numbers match.
JavaScript
const text = "5 dollars and 10 coins";
console.log(text.match(/\d+/g)); // ["5", "10"]
console.log(text.match(/\d+(?! dollars)/g)); // ["10"]
Lookahead differs from the $ anchor, which only checks end-of-string/line.
For “must contain” rules, positive lookahead (?=.*digit) is the usual pattern.
See (x|y) alternation when you need to list allowed forms instead of forbidding one.
Compatibility
Browser & Runtime Support
Negative lookahead (?!...) is part of core JavaScript regular expression syntax.
✓ Baseline · ES3+
RegExp (?!...) lookahead
Supported in every browser and Node.js version. No polyfill needed for negative lookahead assertions.
99%Universal syntax
Google ChromeSupported · Desktop & Mobile
Full support
Mozilla FirefoxSupported · Desktop & Mobile
Full support
Apple SafariSupported · macOS & iOS
Full support
Microsoft EdgeSupported · Chromium
Full support
Internet ExplorerNo native support · Use a polyfill
Polyfill
OperaSupported · Modern versions
Full support
Samsung InternetSupported · Android
Full support
BunSupported · JavaScript runtime
Supported
DenoSupported · JavaScript runtime
Supported
Node.jsSupported · Server runtime
Supported
Android WebViewSupported · Modern WebView
Full support
(?!...)Excellent
Bottom line: Safe everywhere. Use (?!...) when you must exclude specific following text without consuming it.
Wrap Up
Conclusion
The (?!...) negative lookahead lets you match text only when a forbidden pattern does not follow. It is zero-width, precise, and ideal for exclusions—from skipping https when matching http to blocking weak passwords and spam domains.
Remember it is an assertion, not a quantifier like + or *. Pair it with anchors for whole-string rules, use the global flag to find every match, and contrast it with (?=...) when you need the opposite check. Next, learn the + one-or-more quantifier.
Use ^(?!.*forbidden) to ban substrings in whole inputs
Add g when filtering every occurrence in a string
Keep inner lookahead patterns as short and specific as possible
Test edge cases where the forbidden text almost matches
❌ Don’t
Expect lookahead text to appear in the match result
Call (?!...) a repetition quantifier
Over-nest lookaheads without testing readability
Forget to escape dots in domains: @spam\.com
Replace clear alternation when a simple | list is enough
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about (?!...) negative lookahead
Exclude unwanted following text without consuming it.
5
Core concepts
🚫01
(?!...)
Not followed by.
Syntax
👁02
Zero-width
Peek only.
Concept
📈03
Assertion
Not + or *.
Type
🔒04
^(?!.*x)
Ban substring.
Validate
🔄05
(?=...)
Opposite rule.
Compare
❓ Frequently Asked Questions
(?!...) is a negative lookahead assertion. It succeeds when the text immediately after the current position does NOT match the pattern inside the parentheses. It is zero-width—it checks ahead without consuming characters.
No. Although some tutorials label it a quantifier, (?!...) is an assertion (a condition on what follows). Quantifiers like +, *, and ? repeat or optionalize the previous token. Lookahead checks the next characters without including them in the match result.
(?=...) is positive lookahead—it requires the following text to match. (?!...) is negative lookahead—it requires the following text NOT to match. Both are zero-width and do not consume input.
Yes. Write it inside the pattern: /foo(?!bar)/. In the RegExp constructor, escape backslashes: new RegExp('foo(?!bar)'). Lookahead syntax has been supported since early JavaScript (ES3).
Lookahead is ideal when you need to match part of a string only if a specific suffix is absent—without including that suffix in the match. Alternation like /foo|foobaz/ lists allowed forms; (?!...) expresses a rule: match foo unless bar follows.
Negative lookahead is core JavaScript regex syntax since ES3. It works in every modern browser and Node.js version without polyfills.
Did you know?
Lookahead assertions were popularized by Perl and adopted into JavaScript early on. Because they never consume input, you can stack several at one position—for example, a password rule that uses multiple (?=...) and (?!...) checks before matching the actual characters.