Application-level middleware is bound directly to the app object with app.use() or an app.METHOD() call. This lesson covers how to scope it globally or to a specific path prefix.
What Is Application-Level Middleware?
Application-level middleware is registered with app.use([path,] callback). Without a path, it runs for every single request to the app. With a path, it runs only for requests whose URL starts with that path.
This is where most cross-cutting concerns live: request logging, body parsing, CORS, security headers, and authentication checks that should apply broadly.
// runs for every request
app.use((req, res, next) => {
req.requestTime = Date.now();
next();
});
// runs only for requests starting with /admin
app.use('/admin', (req, res, next) => {
if (!req.user?.isAdmin) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
});
The first middleware timestamps every request; the second only guards paths beginning with /admin.
app.use() Syntax
app.use(callback);
app.use(path, callback);
app.use(path, callback1, callback2, ...);
app.use(path, subApp); // mount another Express app
Omitting the path defaults it to '/', matching every request.
A path like '/admin' matches /admin, /admin/users, and any nested path.
You can pass multiple middleware functions (or an array of them) in one app.use() call.
app.use() can even mount an entirely separate Express application as a sub-app.
Application Middleware Cheatsheet
Common ways application-level middleware gets applied.
Pattern
Example
Effect
Global
app.use(morgan('dev'))
Runs for every request
Path-scoped
app.use('/api', apiMiddleware)
Runs only under /api
Multiple functions
app.use('/api', auth, rateLimit)
Both run in order
Array form
app.use([auth, rateLimit])
Same effect as separate arguments
Built-in parser
app.use(express.json())
Parses JSON bodies globally
Ordering Global Middleware Correctly
A very common real-world stack registers security, parsing, and logging middleware near the top of the file, before any routes, so every route automatically benefits from them.
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const morgan = require('morgan');
const app = express();
app.use(helmet());
app.use(cors());
app.use(morgan('dev'));
app.use(express.json());
// routes go after this point
app.use('/api/users', userRouter);
Scoping Middleware by Path Prefix
Path-scoped app.use() is a lightweight way to protect a whole section of an API without adding the same middleware to every individual route.
Both requireAuth and requireAdminRole run before any route inside adminRouter is reached.
Common Mistakes
Registering global middleware after the routes it is supposed to protect or parse for.
Assuming a path prefix like /admin only matches the exact string /admin, it also matches /admin/anything.
Applying expensive middleware (like heavy logging) globally when it's only needed for a subset of routes.
Forgetting that mounting order affects which middleware sees a request first.
Key Takeaways
Application-level middleware is registered with app.use(), globally or scoped to a path prefix.
Security, parsing, and logging middleware typically go near the top, before routes.
Path-scoped middleware is a simple way to protect a whole section of routes at once.
Multiple middleware functions can be chained in a single app.use() call.
Pro Tip
Group your global middleware into one clearly commented block at the top of app.js, so anyone reading the file can see the full request pipeline before they ever reach a single route.
You now understand application-level middleware. Next, see how the same pattern applies to individual routers in the Router Middleware lesson.