app.use vs app.all in Express.js: Key Differences Explained
When working with Express.js, app.use and app.all are two commonly used methods that can look similar at first glance. If you’re new to how Node.js loads these modules in the first place, check out how require() works in CommonJS. But they serve fundamentally different purposes. Understanding the distinction — and how they interact with routers and error handlers — will help you structure your Express applications correctly.
What is app.use?
app.use mounts middleware functions — functions that run before the request reaches a route handler. Middleware has access to req, res, and next.
Key characteristics:
- Used for middleware, not route handling
- Supports partial path matching —
/apimatches/api,/api/users,/api/products/123, etc. - Applies to all HTTP methods (GET, POST, PUT, DELETE…) unless restricted inside the middleware
- Typically calls
next()to pass control to the next middleware or route
app.use('/api', (req, res, next) => {
console.log(`${req.method} ${req.url}`);
next(); // pass control forward
});
This middleware fires for every request whose path starts with /api.
What is app.all?
app.all defines a route handler that responds to all HTTP methods for a specific, exact path.
Key characteristics:
- Used for route handling, not middleware
- Exact path matching —
/useronly matches/user, not/user/profile - Responds directly to requests (usually doesn’t call
next()) - Useful for catch-all handlers and health check endpoints
app.all('/health', (req, res) => {
res.status(200).json({ status: 'ok', timestamp: Date.now() });
});
Side-by-Side Comparison
| Feature | app.use | app.all |
|---|---|---|
| Purpose | Mount middleware | Handle all HTTP methods for a route |
| Path matching | Partial (prefix match) | Exact match only |
| HTTP methods | All | All |
Calls next()? | Usually yes | Usually no |
| Execution order | Before route handlers | After middleware |
| Common uses | Auth, logging, body parsing, CORS | Health checks, catch-all handlers |
Middleware Execution Order
Express processes middleware and routes in the order they are defined. This is critical.
const express = require('express');
const app = express();
// 1. Global middleware — runs for every request
app.use(express.json());
app.use((req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`);
next();
});
// 2. Path-specific middleware — runs only for /api/* routes
app.use('/api', authMiddleware);
// 3. Route handlers — run after middleware
app.get('/api/users', (req, res) => res.json(users));
app.all('/api/health', (req, res) => res.json({ status: 'ok' }));
// 4. 404 handler — runs if nothing matched
app.use((req, res) => res.status(404).json({ error: 'Not found' }));
Real Example: Authentication Middleware with app.use
Here’s a practical auth middleware that protects all /api routes:
function authMiddleware(req, res, next) {
const token = req.headers['authorization']?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded; // attach user to request
next(); // proceed to the route handler
} catch (err) {
return res.status(401).json({ error: 'Invalid token' });
}
}
// Apply to all /api routes
app.use('/api', authMiddleware);
// These routes are protected
app.get('/api/users', (req, res) => {
res.json({ users, requestedBy: req.user.id });
});
// This route is NOT protected (defined before app.use('/api', ...))
app.get('/api/public', (req, res) => {
res.json({ message: 'Public data' });
});
Order matters: Routes defined before
app.use('/api', authMiddleware)are not protected by it. Always define middleware before the routes it should protect.
router.use vs app.use
Express routers let you modularize your application. router.use behaves exactly like app.use but is scoped to the router.
// routes/users.js
const router = express.Router();
// Middleware applied only within this router
router.use((req, res, next) => {
console.log('Users router middleware');
next();
});
router.get('/', (req, res) => res.json(users));
router.get('/:id', (req, res) => res.json(users[req.params.id]));
module.exports = router;
// app.js
const usersRouter = require('./routes/users');
app.use('/api/users', usersRouter); // mount the router
Requests to /api/users and /api/users/123 both go through the router’s internal middleware. Requests to other paths don’t.
Error-Handling Middleware
Error-handling middleware is a special form of app.use with four arguments — Express identifies it by the extra err parameter:
// Regular middleware: 3 arguments
app.use((req, res, next) => { ... });
// Error-handling middleware: 4 arguments
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(err.status || 500).json({
error: err.message || 'Internal server error',
});
});
Always define error-handling middleware last — after all routes and regular middleware.
Triggering Error Middleware
Pass an error to next() from any middleware or route handler:
app.get('/api/data', async (req, res, next) => {
try {
const data = await fetchData();
res.json(data);
} catch (err) {
next(err); // passes to the error-handling middleware
}
});
Common Patterns
CORS Middleware
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if (req.method === 'OPTIONS') {
return res.sendStatus(204);
}
next();
});
Rate Limiting Middleware
const rateLimit = require('express-rate-limit');
app.use('/api', rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per window
message: { error: 'Too many requests' },
}));
Catch-All with app.all
// Respond to all methods on any unmatched /api route
app.all('/api/*', (req, res) => {
res.status(404).json({ error: `Route ${req.path} not found` });
});
FAQs
Q: Can I use app.all to apply middleware?
A: No. app.all is for route handling — it’s meant to send a response. Use app.use for middleware that calls next().
Q: Does app.use work for all HTTP methods?
A: Yes, unless the middleware logic itself restricts by checking req.method.
Q: Can app.all match subpaths like app.use?
A: No. app.all('/user', handler) only matches exactly /user. Use app.all('/user/*', handler) for subpaths.
Q: What’s the difference between app.use and router.use?
A: Same behavior, different scope. app.use applies to the entire application. router.use applies only within that router, which is then mounted at a specific path via app.use.
Q: What happens if I forget to call next() in middleware?
A: The request hangs indefinitely. The client will eventually time out. Always call next(), next(err), or send a response in every middleware code path.
Key Takeaways
app.use= middleware (partial path prefix match, callsnext(), runs before routes).app.all= route handler (exact path match, responds to all HTTP methods, usually sends a response).- Define middleware before the routes it should protect — Express processes in registration order.
- Use
router.useto scope middleware to a specific router, keeping large applications modular. - Error-handling middleware takes 4 arguments
(err, req, res, next)and must be defined last. - Always call
next(err)in async route handlers to route errors to your error middleware.
Related Articles
Node.js File System Module: Read, Write & Manipulate Files
Master the Node.js fs module — async and sync methods for reading, writing, renaming, deleting, watching files, checking metadata with fs.stat, streaming large files, and using fs/promises with async/await.
Node.jsIs Node.js Single-Threaded or Multi-Threaded? A Complete Guide
Understand how Node.js handles concurrency — single-threaded JavaScript execution, the event loop, libuv thread pool, worker threads for CPU tasks, the cluster module, and when to use each approach.
Node.jsHow require() Works in Node.js: CommonJS Module Loading Explained
Deep dive into how Node.js require() resolves module paths, checks the module cache, wraps code in closures, executes modules, returns exports — plus ESM vs CommonJS comparison, dynamic import(), and circular dependency behavior.
Written by
Aditya RawasFull-stack engineer writing deep-dives on JavaScript, TypeScript, React, AWS, Docker, and Kubernetes. Passionate about making complex engineering concepts accessible to developers at every level.