A lookahead is a zero-width regex assertion that checks whether a pattern matches immediately after the current position, without including those characters in the overall match — the engine "looks ahead," confirms the condition, and then continues matching from the same spot it started. It comes in two forms: positive (?=...) and negative (?!...), with a symmetric pair — lookbehind, (?<=...) and (?<!...) — checking what comes before a position instead.
Because a lookahead doesn't consume input, it can be combined with an ordinary pattern to add a condition without changing what actually gets matched:
Positive lookahead: \d+(?=px)
Matches the digits in "16px" (matches "16"), but not in "16em"
— it requires "px" to follow, without including "px" in the match.
Negative lookahead: foo(?!bar)
Matches "foo" in "foo baz", but not in "foobar"
— it requires "bar" to NOT follow.
A classic real-world use is password-strength validation, chaining multiple lookaheads that each check a different condition from the same starting position:
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$
This requires at least one lowercase letter, one uppercase letter, one digit, and a minimum length of 8 — all four assertions are evaluated from position 0, and only the final .{8,} actually consumes (and thus matches) characters.
(?<=...)), or support only fixed-length lookbehind — this is a common source of "works in JavaScript, fails in this other language" bugs.\d+(?!px) does not reject "16px" outright, because after "16" fails the check, the engine backtracks to "1" and re-checks: "6px" doesn't start with "px", so "1" matches. Fixed-length or literal patterns (like the foo(?!bar) example above) don't have this backtracking trap.