Nested Routes
How to work with nested routes in NEMO middleware
Nested Routes
NEMO supports hierarchical organization of middleware through nested routes, allowing you to create advanced routing patterns while maintaining clean code structure.
Basic Nested Routes
You can define nested routes by using objects that contain both a middleware property and additional route keys:
import { createNEMO } from "@zanreal/nemo";
const middleware = createNEMO({
"/admin": {
// Middleware for /admin route
middleware: async (req) => {
req.headers.set("x-section", "admin");
return NextResponse.next();
},
// Nested route for /admin/users
"/users": async (req) => {
// This middleware only runs for /admin/users
return NextResponse.next({
headers: { "x-admin-users": "true" }
});
}
}
});In this example:
- The parent middleware runs for
/adminand any matching child routes - The child middleware runs only for
/admin/users - Both middlewares execute in sequence for matching routes
Execution Order
When a request matches a nested route, NEMO executes the middleware in this order:
- Global
beforemiddleware (if defined) - Root path middleware (
/) for all non-root requests - Parent middleware
- Child middleware
- Global
aftermiddleware (if defined)
If any middleware in the chain returns a response (like a redirect), the chain stops and that response is returned immediately.
Chain Breaking
When a parent middleware returns a response, child middleware will not be executed:
const middleware = createNEMO({
"/protected": {
middleware: (req) => {
// If user is not authenticated, redirect to login
if (!isAuthenticated(req)) {
return NextResponse.redirect("/login");
}
// Otherwise continue to child routes
return NextResponse.next();
},
"/dashboard": (req) => {
// This won't run if the parent redirected
return NextResponse.next({
headers: { "x-dashboard": "true" }
});
}
}
});Deep Nesting with Parameters
You can create deeply nested routes with URL parameters:
const middleware = createNEMO({
"/shop": {
middleware: shopMiddleware,
"/categories": {
middleware: categoriesMiddleware,
"/:categoryId": {
middleware: (req, event) => {
// Access the categoryId parameter
const categoryId = event.params.categoryId;
req.headers.set("x-category-id", categoryId);
return NextResponse.next();
},
"/products": {
middleware: productsMiddleware,
"/:productId": (req, event) => {
const { categoryId, productId } = event.params;
// Both parent and child parameters are available
return NextResponse.next({
headers: {
"x-product-id": productId,
"x-full-path": `category-${categoryId}/product-${productId}`,
},
});
}
}
}
}
}
});In this advanced example, a path like /shop/categories/electronics/products/laptop would execute all middleware in the chain, with event.params containing:
categoryId: "electronics"productId: "laptop"
Important Notes
-
Top-level routes without nesting only match exact paths by default.
// This will ONLY match /foo exactly, not /foo/bar const middleware = createNEMO({ "/foo": fooMiddleware }); -
Parent routes with nested children will match both the exact path and child paths.
// This matches both /parent and /parent/child const middleware = createNEMO({ "/parent": { middleware: parentMiddleware, "/child": childMiddleware } }); -
Parameter matching follows the same rules as regular route matching - parent parameters are available to child routes.