Route Order Matters

First Match Wins — Be Deliberate About Ordering

Route Order Matters

Express tries routes in the order you declared them. Specific before general.

3 min read Level 2/5 #express#routing#order
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()` →