Skip to main content
TF
By Rohit V.7 min readArticle

Regex Greedy vs Lazy Matching Explained (2026)

TF
ToolsFuel Team
Web development tools & tips
Regex Greedy vs Lazy Matching Explained (2026)

Photo by Unsplash on Unsplash

The Short Version

In regular expressions, a quantifier is greedy by default, meaning it matches as much text as it possibly can while still allowing the overall pattern to succeed. Add a `?` after the quantifier and it becomes lazy (also called non-greedy), matching as little as possible. That single character is the difference between a regex that grabs everything and one that stops at the first opportunity.

This is behind one of the most common regex frustrations: 'why is my pattern matching way more than I wanted?' Nine times out of ten, the answer is a greedy quantifier gobbling up text you expected it to leave alone. Once you understand greedy versus lazy, you gain precise control over how much a pattern consumes, and a whole category of baffling regex behavior suddenly makes sense. It's a small concept with an outsized payoff.

What 'Greedy' Actually Means

The quantifiers `*` (zero or more), `+` (one or more), and `{n,}` (n or more) are all greedy by default. Greedy means the engine first tries to match as much as it can, then backtracks — giving characters back one at a time — only if that's necessary for the rest of the pattern to match.

So `.*` doesn't mean 'match a little'; it means 'match absolutely everything you can, then hand back the minimum needed to make the whole pattern work.' That backtracking step is easy to forget, but it's central. The engine is greedy first and reluctant second: it overreaches on purpose, then walks back just enough. Understanding that two-phase behavior — grab everything, then retreat as required — is the key to predicting what a greedy pattern will actually capture, which is often more than beginners expect.

The Classic Example

Nothing makes this concrete like the textbook case. Say you have the string `<b>bold</b>` and you write the pattern `<.*>` hoping to match a single tag. You'd expect it to grab `<b>`. Instead, greedy `.*` matches everything from the first `<` all the way to the *last* `>`, so the whole `<b>bold</b>` gets consumed in one match. The greedy `.*` grabbed as much as it could.

Now make it lazy: `<.*?>`. The `?` after `.*` tells the engine to match as few characters as possible. This time it matches just `<b>`, stops at the first `>`, and if you keep searching it finds `</b>` as a separate match. Same input, one extra character in the pattern, completely different result. This tag example is the canonical demonstration for a reason — it shows greedy overreach and the lazy fix side by side in a way you won't forget.

How to Make a Quantifier Lazy

The mechanic is simple: put a `?` immediately after any quantifier to make it lazy. So `*` becomes `*?`, `+` becomes `+?`, `{2,}` becomes `{2,}?`, and `?` itself (the optional quantifier) can become `??`. In every case, the trailing `?` flips the behavior from 'as much as possible' to 'as little as possible.'

It's worth being careful about the double meaning of `?` here, because it does two different jobs. On its own, `?` means 'zero or one of the preceding thing.' Placed after another quantifier, it means 'be lazy.' So `a?` matches an optional `a`, while `a+?` matches one-or-more `a`s lazily. Context tells you which role the `?` is playing. If regex fundamentals are still shaky for you, my walkthrough on
writing your first regex pattern covers the basics that make this distinction easier to absorb.

When to Use Greedy vs Lazy

Neither mode is 'better' — they're tools for different jobs. Reach for lazy matching when you want the smallest possible chunk, which is common when extracting delimited content: the text between tags, the value inside quotes, the first segment up to a separator. In all those cases you want to stop at the first closing delimiter, and lazy does exactly that.

Greedy matching is the right default when you genuinely want to consume as much as possible, such as trimming everything after a certain point or matching a whole line. Often greedy is simply fine and you never think about it. The trouble only starts when you *assume* a quantifier will stop early and it doesn't. My rule of thumb: if a pattern is capturing more than you intended and there's a repeated delimiter involved, try making the quantifier lazy and see if it snaps to what you wanted. It usually does. A concrete case I hit often is pulling one query parameter out of a URL: greedy will happily run past the delimiter you meant to stop at, so lazy is usually what you want there. If you're working with URLs a lot, it pairs naturally with understanding
URL percent-encoding, since the two problems tend to show up together.

Beware Catastrophic Backtracking

There's a performance trap lurking here that every developer should know about, because it can take down a server. Because greedy quantifiers backtrack, certain patterns — especially nested quantifiers like `(a+)+` applied to input that doesn't match — can force the engine into an astronomical number of backtracking attempts. This is called catastrophic backtracking, and it can freeze a regex for seconds, minutes, or effectively forever on a modest input.

It's a real security concern: attackers deliberately craft inputs to trigger it, a technique known as a regex denial-of-service. The defenses are to avoid nested quantifiers where possible, be specific instead of leaning on broad `.*` patterns, and test your regexes against nasty inputs. Switching to lazy matching doesn't automatically fix catastrophic backtracking, but writing tighter, more specific patterns generally does. When a regex mysteriously hangs, backtracking is almost always the culprit, and it's worth reworking the pattern rather than just throwing more timeout at it.

Test Before You Trust

Regex is famously easy to get subtly wrong, and greedy-versus-lazy bugs are some of the sneakiest because the pattern looks correct and even works on your first test string. Then a slightly different input reveals that it's grabbing too much. So I never ship a non-trivial regex without testing it against several inputs, including edge cases with repeated delimiters.

Interactive regex testers that highlight matches in real time are invaluable here — you paste your pattern and some sample text, and you can literally watch a greedy quantifier swallow more than a lazy one would. Seeing the highlight expand and contract as you add or remove a `?` teaches the concept faster than any explanation. Excellent free references like
MDN's regular expressions guide and community tester sites are worth keeping handy. Test with real, varied data, and greedy-versus-lazy surprises stop reaching production.

The Takeaway

Boil it down and it's genuinely simple: quantifiers are greedy by default and grab as much as they can, and adding a `?` makes them lazy so they grab as little as they can. The classic `<.*>` versus `<.*?>` on an HTML tag shows the whole story — one consumes everything between the first and last delimiter, the other stops at the first.

Use lazy when you want the smallest match up to the nearest delimiter, use greedy when you genuinely want to consume as much as possible, and stay alert to catastrophic backtracking with broad or nested patterns. Master this one distinction and you'll fix the majority of 'my regex matches too much' problems yourself, without the trial-and-error flailing that makes people dread regular expressions in the first place.

Frequently Asked Questions

What is the difference between greedy and lazy in regex?

A greedy quantifier matches as much text as possible while still letting the pattern succeed, then backtracks if needed. A lazy (non-greedy) quantifier, made by adding a ? after the quantifier, matches as little as possible. Greedy grabs everything it can; lazy stops at the first opportunity.

How do I make a regex quantifier lazy?

Add a ? immediately after the quantifier. So * becomes *?, + becomes +?, and {2,} becomes {2,}?. The trailing ? flips the behavior from 'as much as possible' to 'as little as possible.' For example, <.*?> matches a single tag instead of everything between the first and last bracket.

Why does my regex match too much?

Almost always because a quantifier like .* is greedy and consuming more than you expected, running all the way to the last possible delimiter. Making it lazy with .*? usually fixes it by stopping at the first delimiter. This is the most common regex surprise for beginners.

What is catastrophic backtracking?

It's a performance problem where greedy quantifiers, especially nested ones like (a+)+, force the regex engine into an enormous number of backtracking attempts on certain inputs, potentially freezing it. Attackers can exploit it as a denial-of-service. Avoid nested quantifiers and write specific patterns to prevent it.

When should I use greedy vs lazy matching?

Use lazy when you want the smallest chunk, like extracting content between delimiters or inside quotes. Use greedy when you genuinely want to consume as much as possible, like matching a whole line. If a pattern grabs too much around repeated delimiters, try lazy. See my guide on [writing your first regex](/blog/what-is-regex-how-to-write-first-pattern).

Try ToolsFuel

23+ free online tools for developers, designers, and everyone. No signup required.

Browse All Tools