Node.js January 3, 2025 Aditya Rawas

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/api matches /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/user only 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

Featureapp.useapp.all
PurposeMount middlewareHandle all HTTP methods for a route
Path matchingPartial (prefix match)Exact match only
HTTP methodsAllAll
Calls next()?Usually yesUsually no
Execution orderBefore route handlersAfter middleware
Common usesAuth, logging, body parsing, CORSHealth 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, calls next(), 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.use to 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.
Aditya Rawas

Written by

Aditya Rawas

Full-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.