Modules in Depth
Modules in Depth
Modules are how NestJS organises an application into cohesive, self-contained features. A small app might have one module, but real applications are a tree of feature modules — each owning its controllers, services, and dependencies. Mastering modules is what keeps a large codebase navigable.
Feature modules
A feature module groups everything related to one domain. Instead of cramming users, orders, and payments into the root module, each gets its own:
Then you wire it into the root module via imports:
Encapsulation: the key rule
Providers are private to their module by default. If UsersModule declares UsersService in providers but does not export it, no other module can inject it — even if it imports UsersModule.
public vs private in a class.
Shared modules: exporting providers
To let other modules use a provider, add it to the module's exports array:
Now OrdersService can inject UsersService because OrdersModule imports the module that exports it.
Re-exporting modules
A module can import and re-export another module, bundling related capabilities:
Global modules
Some providers are needed almost everywhere — a config service, a logger, a database connection. Marking a module @Global() registers its exports application-wide, so you import it once (in the root module) and inject its providers anywhere without repeating imports:
Summary
Modules organise an app into encapsulated feature units. Providers are private unless exported; other modules gain access by importing the module that exports them. @Global() registers a module's exports everywhere — powerful but to be used sparingly. Next we go under the hood of how NestJS actually resolves these dependencies.