nest-router gave NestJS a path per module, and NestJS then took it
Router Module For Nestjs Framework 🚦 🚀
At a glance
- What is it?
- nest-router is a small NestJS module that prefixes every controller in a module with that module's path, building a route tree from a single routes array. The readme states that the same feature landed in @nestjs/core at Nest v8, so this package is the historical path to that behaviour.
- Who is it for?
- nest-router fits a team on Nest below version 8 that wants path prefixes per module, or a team studying how Nest implemented the feature it later absorbed. It is the wrong dependency for anything new, because the upstream framework does the same job without a third party package.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The readme says the feature moved into the framework
The first section of this readme is an important note rather than a description. As of Nest v8.0.0, the module was added into @nestjs/core, with a link to the Nest documentation for the router module, and the readme adds that this package is still maintained, for now.
That single paragraph reframes the whole project. nest-router is not a piece of infrastructure you choose in the same way as, say, a logger or an ORM adapter. It is a proposal that was accepted upstream, and the community implementation that shipped it first.
The other sign of that history is in the tooling rather than the prose. The package metadata records version 1.0.9, the development dependencies are pinned to the Nest 5 era with @nestjs/common and @nestjs/core at 5.0.0 and @nestjs/testing at 5.3.11, and the test stack is jest at 23 with ts-jest, plus tslint, a travis configuration and wallaby for continuous testing. The examples directory carries three separate sample projects for nest-v4x, nest-v5x and nest-v5x-m2m, which is what a library supporting several major versions of a framework looks like.
The repository is hosted under the nestjsx organisation while the package metadata still points at the original author's repository, and the badges in the readme reference the original owner too. The licence is MIT, with a LICENSE file in the repository root.
The route tree is one array, and the prefix is inherited
The mechanism is a tree of modules, each with a path, and the point of it is that a child inherits its parent's prefix.
Every module can have a path property, and that path becomes a prefix for all the controllers in that module. If a module has a parent, it is a child of it, and its controllers are prefixed by the parent module's prefix plus its own. The readme points at the Nest issue, number 255, that this arrangement answers.
The setup is a routes array passed to RouterModule.forRoutes and imported alongside the modules themselves, so nothing else about the module declaration changes.
const routes: Routes = [
{
path: '/ninja',
module: NinjaModule,
children: [
{
path: '/cats',
module: CatsModule,
},
{
path: '/dogs',
module: DogsModule,
},
],
},
];and the module declaration that consumes it.
@Module({
imports: [
RouterModule.forRoutes(routes), // setup the routes
CatsModule,
DogsModule,
NinjaModule
], // as usual, nothing new
})
export class ApplicationModule {}The behaviour that surprises people is spelled out in the readme. The controllers of the NinjaModule are prefixed with /ninja, and it has two children, CatsModule and DogsModule. The question is whether the controllers of CatsModule are prefixed with /cats, and the answer is no. The CatsModule is a child of NinjaModule, so it is prefixed with /ninja/cats/, and the DogsModule gets the same treatment.
The readme also suggests keeping all of the routes in a separate file such as routes.ts, which is the practical consequence of the design: the whole routing structure of an application ends up readable in one place.
Nested route parameters pass down to the child controllers
Since a child module's controllers sit under the parent's path, a parameter in the parent path is available in the children, and the readme shows how that is written.
const routes: Routes = [
{
path: '/ninja',
module: NinjaModule,
children: [
{
path: '/:ninjaId/cats',
module: CatsModule,
},
{
path: '/:ninjaId/dogs',
module: DogsModule,
},
],
},
];With the parameter placed in the child path rather than the parent, the ninjaId is available inside the controllers of CatsModule and DogsModule, and the readme links to the official Nest documentation for route parameters and suggests using a pipe for transformation so a controller can work with an object rather than a bare id.
The alternative would be to repeat the parameter in every controller, or to put the parameter in the parent path and have it apply to all children. Both work. What the tree gives you is one place where the relationship between a parent resource and its children is written down.
That is the trade in one line. The module tree is a description of your application, and in exchange for that description you accept that the URL shape is decided by the tree rather than by each controller, and that a module's prefix changes when its parent moves.
resolvePath exists because Nest ignores module paths in middleware
One method in this library exists to work around a specific gap in Nest itself, and it is the most telling part of the API.
The readme explains that Nest does not resolve or take into account MODULE_PATH metadata when it comes to resolving a controller path in the middleware resolver. So the ordinary way of attaching middleware to a controller does not see the module prefix.
Instead of
consumer.apply(someMiddleware).forRoutes(SomeController);you write
consumer.apply(someMiddleware).forRoutes(RouterModule.resolvePath(SomeController));and the readme links the pull request that introduced it for more information.
So the library carries both the mechanism and the patch. That is worth noting when you evaluate the package, because it tells you the module path metadata is a Nest feature rather than a nest-router invention, and that the framework version you run determines whether the gap is still there.
It also tells you something about the shape of the tool. It is a thin layer: a routes array, a forRoutes call, a metadata property on each module, and one helper. There is no plugin system, no configuration file and no runtime dependency of its own, which is both its strength and the reason it was easy to fold into the framework.
Installing it takes one line, and a version floor
The installation section is short, with one important constraint.
npm install nest-router --saveor, with yarn,
yarn add nest-routerThe constraint is stated as important: you need Nest greater than v4.5.10. The example projects in the repository cover the v4 line, the v5 line and a v5 module-to-module variant, which is consistent with a library that was written when Nest 4 and 5 were current and then kept working as Nest moved on.
The first real use is the routes array and the import, and the readme recommends starting from the example folder, where the structure is laid out with app.module.ts at the root, a main.ts entry point, and a folder per module holding its controller and module files, with the ninja folder carrying a second controller for a nested resource.
The result of that setup is a route tree you can draw, with the ninja prefix at the top, a katana controller under it, and the cats and dogs modules nested underneath with their own controllers. The readme's own verdict on that picture is a single word, and the reason to care is that a route tree is exactly the thing that is hard to keep in your head when it is spread across a dozen controllers.
Where the package fits in 2026, and where it does not
The honest read of this project is that it is a historical artefact with a still working install path.
What it gives you is a way to declare path prefixes per module and have them inherited, which was a real ergonomic gap in Nest before the framework absorbed it. The mechanism is a Nest metadata property, the routes array is a plain data structure, and the middleware helper exists only because of a specific framework limitation.
What it does not give you is a reason to add a dependency today. The readme says the same feature has been in @nestjs/core since Nest v8, and the documentation link in that note points at the framework's own recipe. A new application on a current Nest version has the capability built in, with the framework's own documentation, its own release cadence and its own bug tracker behind it.
The remaining reasons to use this package are narrow. A team pinned to Nest 5 or 7 can use it and keep the tree style they already have. A team migrating can read this implementation to see exactly what the upstream recipe does, since the two are close enough that the routes array and the forRoutes call are recognisably the same idea. And a developer learning Nest routing gets a small, readable, self-contained implementation of the mechanism.
For a new project, though, the package is the second choice to the framework, and the readme agrees.
Editorial conclusion
nest-router fits a team on Nest below version 8 that wants path prefixes per module, or a team studying how Nest implemented the feature it later absorbed. It is the wrong dependency for anything new, because the upstream framework does the same job without a third party package. Check first which Nest version you are on, since the module path metadata the library depends on is the same mechanism the core router module uses, and confirm that the resolvePath helper for middleware is still needed in your setup before reaching for it.
Frequently asked questions
Do I still need nest-router after Nest v8?
Probably not. The readme states that as of Nest v8.0.0 the module was added into @nestjs/core, linking to the Nest documentation for the router module, and adds that this package is still maintained for now.
How do I install nest-router?
Run npm install nest-router --save or yarn add nest-router. The readme notes that you need Nest greater than v4.5.10.
How does nest-router handle nested module paths?
A child module inherits its parent's prefix, so a CatsModule listed under a /ninja module is prefixed with /ninja/cats rather than /cats. Parameters in the child path are then available in that module's controllers.
Why is RouterModule.resolvePath needed for middleware?
Nest does not take MODULE_PATH metadata into account when it resolves controller paths in the middleware resolver, so the prefix is missing. Using consumer.apply(someMiddleware).forRoutes(RouterModule.resolvePath(SomeController)) supplies the full path.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/nestjsx-nest-router)Was this useful?