In a client router's route table, what does a catch-all segment match that a single dynamic segment cannot?
answer
- the vocabulary a route pattern is written in
- how far does one placeholder reach
- one stops at the separator
- the other takes the remainder
- leftover arrives as segments, possibly empty
basics
~10 sA dynamic segment matches exactly one path segment and stops at the next separator. A catch-all matches the whole remainder of the path, separators included, and hands that leftover over as the captured value.
solid answer
~40 sA route pattern is written in a small vocabulary. A **static** segment must appear literally. A **dynamic** segment is a named placeholder for exactly one segment, so `/docs/:page` matches `/docs/install` but not `/docs/install/windows` — the placeholder stops at the separator. An **optional** segment lets the same entry match with or without that part of the path. A **catch-all** absorbs everything that is left, at any depth, and gives it to the screen as the leftover segments. So use a dynamic segment when the URL carries one identifier, because the narrow pattern already rejects the wrong shape for you; use a catch-all when the depth is genuinely unknown, such as a documentation path, or for the final entry that handles anything unmatched.
code
pseudocode · 9 linestable:
entry "/orders" -> order list
entry "/orders/:id" -> order detail # exactly one segment
entry "/reports/:year?" -> reports # year may be absent
entry "/docs/*rest" -> docs page # rest = remaining segments
entry "*" -> not found
match "/docs/guide/setup" -> entry "/docs/*rest", rest = [guide, setup]
match "/orders/12/edit" -> no entry above matches -> "*"go deeper
Recall the four kinds of segment and the one-segment limit: a placeholder takes a single segment, a catch-all takes everything left. Be able to say which of two URLs a given pattern matches.
Explain the separator boundary as the mechanism, why a narrow pattern is free validation, and what the leftover of a catch-all looks like — including the empty case when that position is optional.
Show the operational angle: too-wide patterns push malformed URLs into screens that then render half-broken states, so choosing narrow patterns removes error handling instead of adding it.
Frame it as a contract: the pattern vocabulary is the app's public URL surface, and every widened pattern is a promise you must keep for bookmarks and shared links long after the screen changes.
## What a route table is A client-side router holds a collection of **entries**. Each entry pairs a **path pattern** with what should be on screen, and usually with extra work attached to that entry — a step that converts captured values into typed data, a data loader, a module to load lazily. **Matching** is the act of walking an incoming path against those patterns and producing two things: the winning entry (or chain of entries) and the **parameters** its pattern captured. The pattern vocabulary is small, and it is almost the same wherever client routing is done, which is why it is worth learning as vocabulary rather than as one product's syntax. ## The four kinds of segment - **Static segment** — literal text that must appear exactly, such as `orders` in `/orders/new`. It captures nothing; it only narrows. - **Dynamic segment** — a named placeholder that matches exactly **one** segment and captures its text, such as the `:id` position in `/orders/:id`. It stops at the next separator. - **Optional segment** — a position that may be absent while the same entry still matches, so one entry can serve `/reports` and `/reports/q3`. The captured value is then either present or missing, and the screen has to cope with both. - **Catch-all segment** — a placeholder for **the rest of the path**, however many segments that is, separators included. The capture arrives as the leftover: usually the list of remaining segments, sometimes the remainder re-joined as one string. | Kind | Matches | Captures | Typical use | |---|---|---|---| | Static | one fixed word | nothing | section names in the URL | | Dynamic | exactly one segment | that segment's text | one identifier or slug | | Optional | that position or its absence | a value or nothing | a page, a year, a tab | | Catch-all | the remainder, any depth | the leftover segments | unknown-depth paths, not-found | ## Where the two get confused Given the path `/docs/guide/setup`, the pattern `/docs/:page` does **not** match: the placeholder can take `guide`, and then `setup` is left over with nothing to match it. A catch-all under `/docs` does match, and the screen receives `guide` and `setup` as the leftover. That separator boundary is the whole difference. The one wrinkle is an **encoded** separator inside a value: because the separator is escaped, it is not a path boundary and one dynamic segment can hold it — which is exactly why a value that may contain separators is awkward in a path segment at all. ## What that means for the screen - A **narrow** pattern is free validation: a malformed, too-deep path simply does not reach the screen, so the screen has fewer states to write. - A **catch-all** defers judgment: any depth matches, so the screen itself must decide that `guide/setup/typo/typo` is nonsense. - The leftover of a catch-all preserves **order** and can be **empty** when the catch-all position is declared optional — a screen that assumes at least one leftover segment will break on the bare parent path. - An **optional** segment means every consumer of that parameter must handle its absence; if the two shapes really render different screens, two entries are clearer than one optional position. ## Choosing between them 1. If the URL carries **one** identifier, use a dynamic segment. The pattern then encodes the shape you expect. 2. If the depth is **data**, not design — a documentation tree, a file path, a nested category — use a catch-all and validate the leftover in the entry. 3. If the same screen has a with-and-without variant that shares its data and its link, use an optional segment instead of a duplicate entry, because a duplicate entry also duplicates link generation. ## The last entry A trailing catch-all is the conventional home of the **not-found** entry: nothing else matched, so the entry that matches everything takes it. Note that *which* pattern wins when several could match — most-specific versus registration order, wildcard precedence — is a separate subject of its own, shared with server-side routers; the vocabulary above is only about what each kind of segment is able to match in the first place.
- When is an optional segment a better choice than registering a second entry?When both shapes render the same screen from the same data and should share one generated link — one entry, one parse step, one place to change. Register two entries when the variants differ in what they load, what they validate, or what they render, because one entry with a branching screen then hides two behaviours behind a single pattern.
- Why is a catch-all a poor pattern for a single identifier?It accepts any depth, so `/orders/12/typo` still matches and the screen must discover the extra segments and decide they are wrong. A one-segment placeholder keeps that path out of the screen entirely, which is one fewer error state to write and one fewer half-rendered screen for the user.
A dynamic segment is a single blank on a form; a catch-all is the open Notes box at the bottom that takes whatever is left, line breaks included.
saying these in an interview costs you the question
- Assumes one dynamic segment can absorb a nested path like a/b
- Believes a static segment also captures a value
- Treats a catch-all match as proof the path is valid
- Expects the leftover of a catch-all to always hold at least one segment
- Thinks an optional segment guarantees the parameter is present anyway