1001Ferramentas
🛣️ Dev

Express Route Pattern Tester

Tests a URL against Express-style route patterns (/users/:id), showing which one matches first, the extracted params and route conflicts.

Supported: :param, :param?, :param(\d+), * at the end for the rest of the path. The query string is separated and never takes part in the match.

How the router picks a route

Express walks the stack in registration order and stops at the first pattern whose regex matches the pathname. A generic /users/:id declared before /users/me swallows the literal route, and no error is raised — the second handler simply never runs. That is why the order block below marks the shadowed patterns.

Params always capture a single segment, so :id never crosses a slash — /files/a/b needs a trailing wildcard. Captured values arrive percent-encoded and Express decodes them, which is why café shows up as caf%C3%A9 in the raw column. Everything here runs in your browser; no pattern or URL is sent anywhere.

Why your Express route is not matching

Paste the patterns in the same order they appear in your routes file and the test answers the question that matters: which handler Express would call for this URL. An app with /users/:id on line 12 and /users/me on line 30 never reaches the second route, because the param swallows the word me and req.params.id ends up holding the string me. The order block marks that shadow line by line.

Each pattern becomes an anchored regex, built segment by segment. A :id captures a single stretch between slashes, so /files/a/b only matches with a wildcard at the end; :cid? makes the whole segment optional rather than just the value; and :id(\d+) swaps the generic group for the regex you wrote. Paste a full URL and the query string stays out of the match and is shown apart, exactly as the router treats it.

The detail that trips up debugging is encoding. Values arrive percent-encoded and are decoded only after the match, so /busca/caf%C3%A9 fills req.params with the accented word, while a broken sequence such as %ZZ throws a URIError out of decodeURIComponent instead of returning a 404. Express ignores letter case by default and treats /a and /a/ as the same route, and the two switches above reproduce that behaviour.

Frequently asked questions

Does this work for Fastify, Koa or React Router?
The colon syntax is the same in all three, and the result usually agrees for simple cases. The differences show at the edges: Fastify uses a prefix tree and prefers the most specific route over the first registered one, and React Router scores segments before picking a winner. For those, use the test to check param extraction and read the order block with a grain of salt.
Why does my literal route never run?
Almost always because a pattern with a param was registered earlier and matches the same URL. Express walks the stack in order and stops at the first hit, with no warning that a compatible route sits further down. The fix is to move literal routes such as /users/me above generic ones such as /users/:id, or to constrain the param with /users/:id(\d+).
How many segments does the wildcard capture?
At the end of a pattern the asterisk captures whatever is left of the path, slashes included: /files/* applied to /files/docs/nota.txt returns docs/nota.txt as a single value. In the middle of a pattern it stands for one segment only, so /a/*/b does not match /a/x/y/b. When you need the whole tail after a prefix, keep the wildcard in the last position.

Related Tools