First Match Wins — Be Deliberate About Ordering
Route Order Matters
Express tries routes in the order you declared them. Specific before general.
What you'll learn
- Order routes from specific to general
- Recognize the common bug
- Use rote ordering for middleware too
Express matches routes in declaration order. The first one that matches wins.
The Classic Bug
app.get("/users/:id", getUserById);
app.get("/users/me", getCurrentUser); What happens when you hit GET /users/me?
:id matches me. getUserById runs with req.params.id === "me".
getCurrentUser never runs.
The Fix — Specific Before General
app.get("/users/me", getCurrentUser); // specific first
app.get("/users/:id", getUserById); // catch-all after Rule of thumb: literal paths before parameter paths.
Multiple Params
app.get("/users/:id/edit", editForm); // ok
app.get("/users/:id", showUser); // ok — different path lengths Different path lengths can’t clash. The conflict is only when the length matches.
Middleware Order
The same rule applies to middleware mounted with app.use():
app.use(logger); // 1st — runs for every request
app.use(express.json()); // 2nd — parses body
app.use("/api", apiAuth); // 3rd — only on /api/*
app.use("/api", apiRouter); // 4th — actual API routes
app.use(errorHandler); // last — catches errors A request flows top to bottom until something responds.
Error Middleware Goes LAST
app.use(routes);
app.use((err, req, res, next) => { /* ... */ }); // ← always last Express only directs errors to middleware that has 4 args, but it won’t reach them if earlier middleware swallowed the request.
Avoiding Order Hell
When a route file is long, group by URL prefix and order within each group from specific to general. Keep the file scannable and order issues stay rare.
`app.param()` →