Express turns the routing patterns you built by hand into a declarative API. This lesson covers route parameters, query strings, and organizing routes with express.Router().
Defining Routes in Express
Express registers routes with method-named functions: app.get(), app.post(), app.put(), app.delete(), and more, each taking a path pattern and one or more handler functions. Dynamic segments in a path are written with a leading colon, /users/:id, and Express automatically extracts them into req.params.
As an app grows, express.Router() lets you group related routes into their own file, then mount that whole group under a path prefix in your main app file, keeping route definitions organized by feature.
Route parameters (:id) are always strings in req.params, even if they look numeric.
req.query holds parsed query string parameters as an object.
express.Router() creates a mini, mountable Express app for grouping related routes.
app.use('/api', router) mounts every route in router under the /api prefix.
Express Routing Cheatsheet
The routing patterns you'll use in nearly every Express app.
Pattern
Example
Static route
app.get('/health', handler)
Route parameter
app.get('/users/:id', handler)
Multiple parameters
app.get('/posts/:postId/comments/:id', handler)
Query string
req.query.page
Grouped routes
const router = express.Router();
Mounted router
app.use('/api/users', userRouter);
Organizing Routes With express.Router()
In any Express app beyond a handful of routes, defining everything directly on app becomes unwieldy. express.Router() lets you split routes by resource (users, posts, orders) into their own files, then combine them in your main entry file.
Just like the hand-rolled router from earlier lessons, Express checks routes in registration order. A dynamic route registered before a more specific static one can shadow it unintentionally.
// Wrong order: /users/:id will match "/users/new" too
app.get('/users/:id', getUserById);
app.get('/users/new', showNewUserForm);
// Correct order: specific routes first
app.get('/users/new', showNewUserForm);
app.get('/users/:id', getUserById);
Common Mistakes
Registering a dynamic route before a more specific static route that it accidentally shadows.
Forgetting that req.params values are always strings, even for numeric-looking IDs.
Defining every route directly on app instead of splitting them with express.Router() as the app grows.
Mismatching the router's mount path with the paths defined inside the router itself.
Key Takeaways
Express routes are defined with method-named functions taking a path pattern and handler.
express.Router() groups related routes into a separate, mountable module.
Route registration order determines which route wins when patterns overlap.
Pro Tip
Split routes by resource (routes/users.js, routes/orders.js) from the very start of a project, even a small one. Retrofitting this structure later on a large app.js file full of routes is far more painful than starting with it.
You now know how Express routing works. Next, explore Express Middleware, the layer that handles cross-cutting concerns cleanly.