- Express.js Basics
- Express.js HOME
- Express.js Introduction
- Express.js Installation
- Express.js Basic App
- Express.js Routing
- Basics Routing
- Route Parameters
- Handling Query Strings
- Router Middleware
- Middleware
- What is Middleware?
- Application-Level Middleware
- Router-Level Middleware
- Built-In Middleware
- Error-Handling Middleware
- Third-Party Middleware
- Express.js HTTP
- Handling GET Requests
- Handling POST Requests
- Handling PUT Requests
- Handling DELETE Requests
- Templating Engines
- Using Templating Engines
- Setting Up EJS
- Setting Up Handlebars
- Setting Up Pug
- Request/Response
- Request Object
- Response Object
- Handling JSON Data
- Handling Form Data
- Static Files
- Serving Static Files
- Setting Up Static Folders
- Managing Assets
- Express.js Advanced
- Middleware Stack
- CORS in Express.js
- JWT Authentication
- Session Handling
- File Uploads
- Error Handling
- Databases
- Express.js with MongoDB
- MongoDB CRUD Operations
- Express.js with MySQL
- MySQL CRUD Operations
- Deployment
- Deploying Express.js Apps to Heroku
- Deploying Express.js Apps to AWS
- Deploying Express.js Apps to Vercel
Express.js Router-Level Middleware
In Express.js, middleware is the backbone of your request-handling logic. While application-level middleware runs for every single request your server receives, Router-level middleware allows you to be much more surgical. It is bound to an instance of express.Router(), meaning you can group related routes (like all /api routes or all /admin routes) and apply specific logic only to that group.
Think of it as a localized "gatekeeper" that only cares about a specific subset of your application's URLs. This keeps your code clean, modular, and easy to debug.
/v1 router while leaving your /v2 router untouched.
Key Features of Router-Level Middleware
- Logical Modularization: You can split your app into logical sections (e.g., users, products, billing) and give each its own middleware stack.
- Scoped Execution: Middleware only triggers for routes defined within that specific router instance.
- Middleware Chaining: You can stack multiple middleware functions to run in a specific order before the final route handler is reached.
- Granular Control: It works perfectly alongside global application-level middleware, allowing for multi-layered security or logging.
app.js file clean by defining routers in separate files and importing them. This makes your codebase much easier for other developers to navigate.
Steps to Implement Router-Level Middleware
1. Set up a Basic Express Application
First, initialize your project directory and install the necessary dependencies:
npm init -y
npm install express --save
2. Create a Router and Apply Middleware
The express.Router() function creates a mini-app that can have its own middleware and routes. Here is how you define a router and apply middleware to it:
const express = require('express');
const app = express();
const router = express.Router();
// This middleware will run for ANY request that enters this router
router.use((req, res, next) => {
console.log(`[${new Date().toISOString()}] Request made to: ${req.originalUrl}`);
next(); // Always call next() to move to the next function in the stack
});
// Define routes bound to this router
router.get('/', (req, res) => {
res.send('Welcome to the Dashboard!');
});
router.get('/settings', (req, res) => {
res.send('User Settings Page');
});
// Attach the router to a specific base path (e.g., /dashboard)
app.use('/dashboard', router);
app.listen(3000, () => {
console.log('Server is live at http://localhost:3000');
});
next() inside your middleware, the request will hang indefinitely, and the browser will eventually timeout.
3. Test Router-Level Middleware
Start your server using node app.js. When you visit the following URLs, you will see the timestamps logged in your terminal:
http://localhost:3000/dashboard/http://localhost:3000/dashboard/settings
Note that if you added a generic route like app.get('/home') in your main file, the router-level middleware would not execute for it.
4. Use Router-Level Middleware for Specific Routes
Sometimes you don't want middleware to run for the entire router, but only for a specific path within that router. This is great for things like specific form validation:
// This middleware only triggers when accessing /about
router.use('/about', (req, res, next) => {
console.log('Accessing the About section...');
next();
});
router.get('/about', (req, res) => {
res.send('This is a modular About route.');
});
router.use() after your route definitions. Express executes middleware in the order it is defined. If you place your middleware after router.get(), the route handler will finish the request before the middleware ever gets a chance to run.
5. Router-Level Error-Handling Middleware
Error-handling middleware is unique because it takes four arguments instead of three. Placing it at the end of your router allows you to catch errors specific to that module:
// Error-handling middleware for the router
router.use((err, req, res, next) => {
console.error('Error detected in Dashboard Router:', err.message);
res.status(500).send('The dashboard encountered an internal error.');
});
Example of Modularized Router with Multiple Middleware
In a real-world scenario, you might have an Auth middleware that checks if a user is logged in before allowing them to access an Admin panel. Here is how you can separate those concerns:
const express = require('express');
const app = express();
// User Router Logic
const userRouter = express.Router();
userRouter.use((req, res, next) => {
console.log('Running User-specific logic');
next();
});
userRouter.get('/profile', (req, res) => res.send('User Profile'));
// Admin Router Logic
const adminRouter = express.Router();
// Simulated Auth Middleware
const checkAdmin = (req, res, next) => {
const isAdmin = req.headers['admin-token'] === 'secret-key';
if (isAdmin) {
next();
} else {
res.status(403).send('Access Denied: Admins Only');
}
};
// Apply auth check to the entire admin router
adminRouter.use(checkAdmin);
adminRouter.get('/dashboard', (req, res) => {
res.send('Secret Admin Dashboard');
});
// Mount routers to specific paths
app.use('/user', userRouter);
app.use('/admin', adminRouter);
app.listen(3000);
router.use() call or a route handler, like: router.get('/data', validateInput, checkAuth, (req, res) => { ... });.
- Requests to
/user/profilewill trigger the user middleware but will NOT require an admin token. - Requests to
/admin/dashboardwill trigger thecheckAdminmiddleware. If the header is missing, the request is blocked before it even hits the dashboard route.
Summary
Router-level middleware is an essential tool for any Express developer looking to build scalable applications. By scoping middleware to specific express.Router() instances, you ensure that your code remains "DRY" (Don't Repeat Yourself) and highly organized. Whether you are performing authentication checks, logging API calls, or parsing specific headers, using routers allows you to keep your application logic clean and maintainable as it grows from a simple script into a production-grade API.