Middleware intercepts incoming requests before application logic, validates or transforms them, and either continues processing or returns a response. In security-sensitive applications, place it at the beginning of the request pipeline so every request is checked before reaching core logic. section 9.1.2
A production middleware pipeline can combine independent controls:
- Authenticate requests and protect selected routes. section 9.3.1
- Handle CORS by allowing specific origins and blocking unauthorized cross-origin access. section 10.2
- Apply rate limits to restrict excessive requests and reduce abuse. section 9.1.2
- Set security headers before requests reach application handlers. section 10.2
Protecting a Next.js chat route
Clerk middleware can match /chat and its API routes, require authentication, then apply CORS and rate limiting. Unauthenticated visitors are redirected to /sign-in, while authenticated visitors continue to /chat. section 9.3.1
Listing 9.2 Composable middleware
import { NextResponse } from 'next/server';
const composeMiddleware = (middlewares) => { #1
return async (request) => {
let response = NextResponse.next();
for (const middleware of middlewares) {
try {
const result =
await middleware(request, response); #2
if (result.response) return result.response;
if (result.continue === false) break;
} catch (error) {
console.error('Middleware error:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}
return response;
};
};
const middlewareChain = composeMiddleware([ #3
handleCORS,
rateLimit,
authenticate,
securityHeaders,
]);
export async function middleware(request) { #4
return await middlewareChain(request);
}
export const config = { #5
matcher: '/api/:path*',
};
A composable implementation runs middleware sequentially. Each function can modify the response, return a response to short-circuit the chain, stop continuation, or fail into a 500 response. section 9.1.2









