Express.js Routing Basics
Routing is the mechanism that matches an incoming request URL to a specific function in your code. When a browser sends a request to your server, Express looks at the URL and the HTTP method, finds the matching route, and runs the function you defined for it. This topic covers how routing works, the different ways to define routes, and how to handle multiple URL patterns.
The Routing Concept: A Post Office Analogy
Think of Express routing like a post office sorting room. Every incoming letter (request) has an address (URL) and a type label (HTTP method). Workers in the sorting room (Express) read the address and label, then send the letter to the correct desk (route handler). The worker at that desk opens the letter, processes it, and sends a reply (response) back.
Incoming Request │ │ URL: /products │ Method: GET ▼ Express Routing Table: ┌──────────────────────────────────────────────────────┐ │ GET / → Show homepage │ │ GET /about → Show about page │ │ GET /products → Show product list ← MATCH ✓ │ │ POST /products → Add a new product │ │ GET /contact → Show contact form │ └──────────────────────────────────────────────────────┘ │ ▼ Handler runs → sends response back to browser
Basic Route Syntax
Every route in Express follows the same pattern:
app.METHOD(PATH, HANDLER);
Break that down:
- app — your Express application instance
- METHOD — the HTTP method in lowercase:
get,post,put,delete - PATH — the URL path as a string, like
'/'or'/products' - HANDLER — the function that runs when the route matches
app.get('/products', (req, res) => {
res.send('List of all products');
});
Defining Multiple Routes
A real application needs many routes. Define them one after the other, and Express checks them from top to bottom until it finds a match:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Home Page');
});
app.get('/about', (req, res) => {
res.send('About Us');
});
app.get('/services', (req, res) => {
res.send('Our Services');
});
app.get('/contact', (req, res) => {
res.send('Contact Page');
});
app.listen(3000);
Each URL maps to its own handler function. None of the routes interfere with each other.
How Express Matches Routes: Top to Bottom
Express reads your routes in the order you define them. When a request arrives, Express checks the first route. If it matches, that handler runs and the search stops. If it does not match, Express moves to the next route.
Request: GET /services
Check app.get('/') → No match
Check app.get('/about') → No match
Check app.get('/services') → MATCH → handler runs → search stops
This top-to-bottom behavior matters when routes could conflict. Always put more specific routes before general ones.
Route Paths with Patterns
Route paths can use special pattern characters for flexible matching:
Question Mark: Optional Character
app.get('/colo?r', (req, res) => {
res.send('Matches /color or /colour');
});
The ? makes the character before it optional. This route matches both /color and /colour.
Plus Sign: One or More
app.get('/ab+c', (req, res) => {
res.send('Matches /abc, /abbc, /abbbc...');
});
Asterisk: Any Characters
app.get('/user*', (req, res) => {
res.send('Matches /user, /username, /user-profile...');
});
The Catch-All Route (404 Handler)
Place a catch-all route at the very end of your route list. It matches any URL that did not match an earlier route. This is how you send a custom 404 page:
// All your normal routes go here
app.get('/', (req, res) => { res.send('Home'); });
app.get('/about', (req, res) => { res.send('About'); });
// This catch-all MUST be last
app.use((req, res) => {
res.status(404).send('Page Not Found');
});
app.use() without a path matches every request. Since it sits at the bottom, it only catches requests that fell through all the defined routes above it.
Sending Different Response Types
Routes can send different types of content using different response methods:
┌──────────────────────────────────────────────────────────────┐
│ Response Methods │
├──────────────────────┬───────────────────────────────────────┤
│ res.send('text') │ Sends plain text or HTML │
│ res.json({ key: v }) │ Sends JSON data │
│ res.sendFile(path) │ Sends a file to the browser │
│ res.redirect('/url') │ Redirects to another URL │
│ res.status(404) │ Sets the HTTP status code │
│ res.render('view') │ Renders a template file │
└──────────────────────┴───────────────────────────────────────┘
Chain res.status() with other methods to set the status and send a response together:
app.get('/not-found', (req, res) => {
res.status(404).send('This page does not exist');
});
Sending JSON Responses
APIs return data in JSON format. Use res.json() to send a JavaScript object as JSON:
app.get('/api/user', (req, res) => {
res.json({
name: 'Alice',
age: 30,
role: 'developer'
});
});
The browser or API client receives:
{
"name": "Alice",
"age": 30,
"role": "developer"
}
app.all(): Match All HTTP Methods
app.all() matches a path regardless of which HTTP method the client uses. It is useful for logging or access control that applies to all methods on a route:
app.all('/admin', (req, res) => {
res.send('Admin area - all methods land here');
});
Route Chaining with app.route()
When one URL handles multiple HTTP methods, you can chain them together using app.route() to keep the code organized:
app.route('/book')
.get((req, res) => {
res.send('Get a book');
})
.post((req, res) => {
res.send('Add a book');
})
.delete((req, res) => {
res.send('Delete a book');
});
All three methods share the same path /book but run different functions.
Visual Summary of Routing
HTTP Request
│
┌────────────▼────────────┐
│ Express Router │
│ │
│ GET / → handler A │
│ GET /about → handler B│
│ POST /data → handler C │
│ * (any) → 404 page │
└────────────┬────────────┘
│ matched route
▼
Handler Function
(req, res) => { ... }
│
▼
Response
(HTML / JSON / File)
Summary
Express routing maps URLs and HTTP methods to handler functions. Use app.get(), app.post(), app.put(), and app.delete() to define routes for specific methods. Express checks routes top to bottom and stops at the first match. Place a catch-all route at the end to handle 404 errors. Use res.send() for text, res.json() for API data, and res.redirect() to send users to a different URL. Group multiple methods on one path using app.route() for cleaner code.
