NgModules help organize an application into cohesive blocks of functionality.
An NgModule is a class adorned with the @NgModule decorator function.
@NgModule takes a metadata object that tells Angular how to compile and run module code.
It identifies the module's own components, directives, and pipes,
making some of them public so external components can use them.
@NgModule may add service providers to the application dependency injectors.
And there are many more options covered here.
Before reading this page, read the
The Root Module page, which introduces NgModules and the essentials
of creating and maintaining a single root
AppModule for the entire application.
This page covers NgModules in greater depth.
Table of Contents
- Angular modularity
- The application root module
- Bootstrap the root module
- Resolve conflicts
- Feature modules
- Lazy loaded modules with the router
- Shared modules
- The Core module
- Configure core services with forRoot
- Prevent reimport of the CoreModule
- NgModule metadata properties
This page explains NgModules through a progression of improvements to a sample with a "Tour of Heroes" theme. Here's an index to live examples at key moments in the evolution of the sample:
A minimal NgModule app The first contact module The revised contact module Just before adding SharedModule The final version
Frequently asked questions (FAQs)
This page covers NgModule concepts in a tutorial fashion.
The companion NgModule FAQs cookbook offers answers to specific design and implementation questions. Read this page before reading those FAQs.
Modules are a great way to organize an application and extend it with capabilities from external libraries.
Many Angular libraries are modules (such as
Many third-party libraries are available as NgModules (such as
NgModules consolidate components, directives, and pipes into cohesive blocks of functionality, each focused on a feature area, application business domain, workflow, or common collection of utilities.
Modules can also add services to the application. Such services might be internally developed, such as the application logger. Services can come from outside sources, such as the Angular router and Http client.
Modules can be loaded eagerly when the application starts. They can also be lazy loaded asynchronously by the router.
An NgModule is a class decorated with
@NgModule metadata. The metadata do the following:
- Declare which components, directives, and pipes belong to the module.
- Make some of those classes public so that other component templates can use them.
- Import other modules with the components, directives, and pipes needed by the components in this module.
- Provide services at the application level that any application component can use.
Every Angular app has at least one module class, the root module. You bootstrap that module to launch the application.
The root module is all you need in a simple application with a few components. As the app grows, you refactor the root module into feature modules that represent collections of related functionality. You then import these modules into the root module.
Later in this page, you'll read about this process. For now, you'll start with the root module.
AppModule: the application root module
Every Angular app has a root module class.
By convention, the root module class is called
AppModule and it exists in a file named
AppModule from the QuickStart seed on the Setup page is as minimal as possible:
@NgModule decorator defines the metadata for the module.
This page takes an intuitive approach to understanding the metadata and fills in details as it progresses.
The metadata imports a single helper module,
BrowserModule, which every browser app must import.
BrowserModule registers critical application service providers.
It also includes common directives like
NgFor, which become immediately visible and usable
in any of this module's component templates.
declarations list identifies the application's only component,
the root component, the top of the app's rather bare component tree.
AppComponent simply displays a data-bound title:
@NgModule.bootstrap property identifies this
AppComponent as the bootstrap component.
When Angular launches the app, it places the HTML rendering of
AppComponent in the DOM,
<my-app> element tags of the
Bootstrapping in main.ts
You launch the application by bootstrapping the
AppModule in the
Angular offers a variety of bootstrapping options targeting multiple platforms. This page describes two options, both targeting the browser.
Dynamic bootstrapping with the just-in-time (JIT) compiler
In the first, dynamic option, the Angular compiler compiles the application in the browser and then launches the app.
The samples in this page demonstrate the dynamic bootstrapping approach.
Static bootstrapping with the ahead-of-time (AOT) compiler
Consider the static alternative which can produce a much smaller application that launches faster, especially on mobile devices and high latency networks.
In the static option, the Angular compiler runs ahead of time as part of the build process,
producing a collection of class factories in their own files.
Among them is the
The syntax for bootstrapping the pre-compiled
AppModuleNgFactory is similar to
the dynamic version that bootstraps the
Because the entire application was pre-compiled, Angular doesn't ship the Angular compiler to the browser and doesn't compile in the browser.
The application code downloaded to the browser is much smaller than the dynamic equivalent and it's ready to execute immediately. The performance boost can be significant.
Both the JIT and AOT compilers generate an
AppModuleNgFactory class from the same
The JIT compiler creates that factory class on the fly, in memory, in the browser.
The AOT compiler outputs the factory to a physical file
that is imported here in the static version of
In general, the
AppModule should neither know nor care how it is bootstrapped.
AppModule evolves as the app grows, the bootstrap code in
main.ts doesn't change.
This is the last time you'll look at
Declare directives and components
As the app evolves,
the first addition is a
HighlightDirective, an attribute directive
that sets the background color of the attached element.
AppComponent template to attach the directive to the title:
If you ran the app now, Angular wouldn't recognize the
highlight attribute and would ignore it.
You must declare the directive in
HighlightDirective class and add it to the module's
declarations like this:
Add a component
Refactor the title into its own
The component's template binds to the component's
subtitle properties like this:
AppComponent to display the new
TitleComponent in the
using an input binding to set the
Angular won't recognize the
<app-title> tag until you declare it in
TitleComponent class and add it to the module's
Modules are a great way to provide services for all of the module's components.
The Dependency Injection page describes the Angular hierarchical dependency-injection system and how to configure that system with providers at different levels of the application's component tree.
A module can add providers to the application's root dependency injector, making those services available everywhere in the application.
Many applications capture information about the currently logged-in user and make that information
accessible through a user service.
This sample application has a dummy implementation of such a
The sample application should display a welcome message to the logged-in user just below the application title.
TitleComponent template to show the welcome message below the application title.
TitleComponent class with a constructor that injects the
and sets the component's
user property from the service.
You've defined and used the service. Now to provide it for all components to use,
add it to a
providers property in the
Import supporting modules
In the revised
*ngIf directive guards the message.
There is no message if there is no user.
AppModule doesn't declare
NgIf, the application still compiles and runs.
How can that be? The Angular compiler should either ignore or complain about unrecognized HTML.
Angular does recognize
NgIf because you imported it earlier.
The initial version of
BrowserModule made all of its public components, directives, and pipes visible
to the component templates in
NgIf is declared in
CommonModule contributes many of the common directives that applications need, including
CommonModule and re-exports it.
The net effect is that an importer of
CommonModule directives automatically.
Many familiar Angular directives don't belong to
RouterLink belong to Angular's
You must import those modules before you can use their directives.
To illustrate this point, you'll extend the sample app with
a form component that imports form support from the Angular
Add the ContactComponent
Angular forms are a great way to manage user data entry.
ContactComponent presents a "contact editor,"
implemented with Angular forms in the template-driven form style.
Angular form styles
You can write Angular form components in template-driven or reactive style.
The following sample imports the
ContactComponent is written in template-driven style.
Modules with components written in the reactive style
ContactComponent selector matches an element named
Add an element with that name to the
AppComponent template, just below the
Form components are often complex. The
ContactComponent has its own
and custom pipe (called
and an alternative version of the
To make it manageable, place all contact-related material in an
and break the component into three constituent HTML, TypeScript, and css files:
In the middle of the component template,
notice the two-way data binding
ngModel is the selector for the
NgModel is an Angular directive, the Angular compiler won't recognize it for the following reasons:
NgModelwasn't imported via
Even if Angular somehow recognized
ContactComponent wouldn't behave like an Angular form because
form features such as validation aren't yet available.
Import the FormsModule
FormsModule to the
[(ngModel)] binding will work and the user input will be validated by Angular forms,
once you declare the new component, pipe, and directive.
Do not add
AppModule metadata's declarations.
These directives belong to the
Components, directives, and pipes belong to one module only.
Never re-declare classes that belong to another module.
Declare the contact component, directive, and pipe
The application won't compile until you declare the contact component, directive, and pipe.
declarations in the
There are two directives with the same name, both called
To work around this, create an alias for the contact version using the
This solves the immediate issue of referencing both directive types in the same file but leaves another issue unresolved. You'll learn more about that issue later in this page, in Resolve directive conflicts.
Provide the ContactService
ContactComponent displays contacts retrieved by the
which Angular injects into its constructor.
You have to provide that service somewhere.
ContactComponent could provide it,
but then the service would be scoped to this component only.
You want to share this service with other contact-related components that you'll surely add later.
In this app, add
ContactService to the
Now you can inject
UserService) into any component in the application.
ContactService provider is application-scoped because Angular
registers a module's
providers with the application's root injector.
ContactService belongs to the Contact business domain.
Classes in other domains don't need the
ContactService and shouldn't inject it.
You might expect Angular to offer a module-scoping mechanism to enforce this design. It doesn't. NgModule instances, unlike components, don't have their own injectors so they can't have their own provider scopes.
This omission is intentional. NgModules are designed primarily to extend an application, to enrich the entire app with the module's capabilities.
In practice, service scoping is rarely an issue.
Non-contact components can't accidentally inject the
ContactService, you must first import its type.
Only Contact components should import the
Run the app
Everything is in place to run the application with its contact editor.
The app file structure looks like this:
Try the example:
Resolve directive conflicts
An issue arose earlier when you declared the contact's
you already had a
HighlightDirective class at the application level.
The selectors of the two directives both highlight the attached element with a different color.
Both directives are declared in this module so both directives are active.
When the two directives compete to color the same element,
the directive that's declared later wins because its DOM changes overwrite the first.
In this case, the contact's
HighlightDirective makes the application title text blue
when it should stay gold.
The issue is that two different classes are trying to do the same thing.
It's OK to import the same directive class multiple times. Angular removes duplicate classes and only registers one of them.
But from Angular's perspective, two different classes, defined in different files, that have the same name are not duplicates. Angular keeps both directives and they take turns modifying the same HTML element.
At least the app still compiles. If you define two different component classes with the same selector specifying the same element tag, the compiler reports an error. It can't insert two components in the same DOM location.
To eliminate component and directive conflicts, create feature modules that insulate the declarations in one module from the declarations in another.
This application isn't big yet, but it's already experiencing structural issues.
- The root
AppModulegrows larger with each new application class.
- There are conflicting directives.
HighlightDirectivein the contact re-colors the work done by the
AppModule. Also, it colors the application title text when it should color only the
- The app lacks clear boundaries between contact functionality and other application features. That lack of clarity makes it harder to assign development responsibilities to different teams.
You can resolve these issues with feature modules.
A feature module is a class adorned by the
@NgModule decorator and its metadata,
just like a root module.
Feature module metadata have the same properties as the metadata for a root module.
The root module and the feature module share the same execution context. They share the same dependency injector, which means the services in one module are available to all.
The modules have the following significant technical differences:
- You boot the root module to launch the app; you import a feature module to extend the app.
- A feature module can expose or hide its implementation from other modules.
Otherwise, a feature module is distinguished primarily by its intent.
A feature module delivers a cohesive set of functionality focused on an application business domain, user workflow, facility (forms, http, routing), or collection of related utilities.
While you can do everything within the root module, feature modules help you partition the app into areas of specific interest and purpose.
A feature module collaborates with the root module and with other modules through the services it provides and the components, directives, and pipes that it shares.
In the next section, you'll carve the contact functionality out of the root module and into a dedicated feature module.
Make Contact a feature module
It's easy to refactor the contact material into a contact feature module.
- Create the
- Move the contact material from
- Replace the imported
- Import the
AppModule is the only existing class that changes. But you do add one new file.
Add the ContactModule
Here's the new
You copy from
AppModule the contact-related import statements and
that concern the contact, and paste them into
You import the
FormsModule because the contact component needs it.
Modules don't inherit access to the components, directives, or pipes that are declared in other modules.
AppModule imports is irrelevant to
ContactModule and vice versa.
ContactComponent can bind with
ContactModule must import
You also replaced
CommonModule, for reasons explained in the
Should I import BrowserModule or CommonModule?
section of the NgModule FAQs page.
You declare the contact component, directive, and pipe in the module
You export the
other modules that import the
ContactModule can include it in their component templates.
All other declared contact classes are private by default.
HighlightDirective are hidden from the rest of the application.
HighlightDirective can no longer color the
AppComponent title text.
Refactor the AppModule
Return to the
AppModule and remove everything specific to the contact feature set.
- Delete the contact import statements.
- Delete the contact declarations and contact providers.
- Delete the
AppComponentdoesn't need it).
Leave only the classes required at the application root level.
Then import the
ContactModule so the app can continue to display the exported
Here's the refactored version of the
AppModule along with the previous version.
There's a lot to like in the revised
- It does not change as the Contact domain grows.
- It only changes when you add new modules.
- Fewer import statements.
- No contact-specific declarations.
ContactModule version of the sample.
Lazy-loading modules with the router
The Heroic Staffing Agency sample app has evolved. It has two more modules, one for managing the heroes on staff and another for matching crises to the heroes. Both modules are in the early stages of development. Their specifics aren't important to the story and this page doesn't discuss every line of code.
Examine and download the complete source for this version from
Some facets of the current application merit discussion are as follows:
- The app has three feature modules: Contact, Hero, and Crisis.
- The Angular router helps users navigate among these modules.
ContactComponentis the default destination when the app starts.
ContactModulecontinues to be "eagerly" loaded when the application starts.
CrisisModuleare lazy loaded.
AppComponent template has
a title, three links, and a
<app-contact> element is gone; you're routing to the Contact page now.
AppModule has changed modestly:
Some file names bear a
.3 extension that indicates
a difference with prior or future versions.
The significant differences will be explained in due course.
The module still imports
ContactModule so that its routes and components are mounted when the app starts.
The module does not import
They'll be fetched and mounted asynchronously when the user navigates to one of their routes.
The significant change from version 2 is the addition of the AppRoutingModule to the module
AppRoutingModule is a routing module
that handles the app's routing concerns.
The router is the subject of the Routing & Navigation page, so this section skips many of the details and concentrates on the intersection of NgModules and routing.
app-routing.module.ts file defines three routes.
The first route redirects the empty URL (such as
to another route whose path is
contact (such as
contact route isn't defined here.
It's defined in the Contact feature's own routing module,
It's standard practice for feature modules with routing components to define their own routes.
You'll get to that file in a moment.
The remaining two routes use lazy loading syntax to tell the router where to find the modules:
A lazy-loaded module location is a string, not a type.
In this app, the string identifies both the module file and the module class,
the latter separated from the former by a
forRoot static class method of the
RouterModule with the provided configuration and
added to the
imports array provides the routing concerns for the module.
AppRoutingModule class is a
Routing Module containing both the
and the dependency-injection providers that produce a configured
AppRoutingModule is intended for the app root module only.
RouterModule.forRoot in a feature-routing module.
Back in the root
AppModule, add the
AppRoutingModule to its
and the app is ready to navigate.
Routing to a feature module
src/app/contact folder holds a new file,
It defines the
contact route mentioned earlier and provides a
ContactRoutingModule as follows:
This time you pass the route list to the
forChild method of the
The route list is only responsible for providing additional routes and is intended for feature modules.
RouterModule.forChild in a feature-routing module.
forRoot and forChild are conventional names for methods that
import values to root and feature modules.
Angular doesn't recognize them but Angular developers do.
ContactModule has changed in two small but important ways.
- It imports the
- It no longer exports
Now that you navigate to
ContactComponent with the router, there's no reason to make it public.
ContactComponent doesn't need a selector.
No template will ever again reference this
It's gone from the AppComponent template.
Lazy-loaded routing to a module
CrisisModule follow the same principles as any feature module.
They don't look different from the eagerly loaded
HeroModule is a bit more complex than the
CrisisModule, which makes it
a more interesting and useful example. Its file structure is as follows:
This is the child routing scenario familiar to readers of the
Child routing component section of the
Routing & Navigation page.
HeroComponent is the feature's top component and routing host.
Its template has a
<router-outlet> that displays either a list of heroes (
or an editor of a selected hero (
Both components delegate to the
HeroService to fetch and save data.
HighlightDirective colors elements in yet a different shade.
In the next section, Shared modules, you'll resolve the repetition and inconsistencies.
HeroModule is a feature module like any other.
It imports the
FormsModule because the
HeroDetailComponent template binds with
It imports the
hero-routing.module.ts just as
CrisisModule is much the same.
The app is shaping up.
But it carries three different versions of the
And the many files cluttering the app folder level could be better organized.
SharedModule to hold the common components, directives, and pipes
and share them with the modules that need them.
- Create an
- Move the
- Delete the
- Create a
SharedModuleclass to own the shared material.
- Update other feature modules to import
Here is the
Note the following:
- It imports the
CommonModulebecause its component needs common directives.
- It declares and exports the utility pipe, directive, and component classes as expected.
- It re-exports the
Re-exporting other modules
If you review the application, you may notice that many components requiring
and bind to component properties with
[(ngModel)], a directive in the
Modules that declare these components would have to import
You can reduce the repetition by having
so that importers of
FormsModule for free.
As it happens, the components declared by
SharedModule itself don't bind with
Technically, there is no need for
SharedModule to import
SharedModule can still export
FormsModule without listing it among its
Why TitleComponent isn't shared
SharedModule exists to make commonly used components, directives, and pipes available
for use in the templates of components in many other modules.
TitleComponent is used only once by the
There's no point in sharing it.
Why UserService isn't shared
While many components share the same service instances, they rely on Angular dependency injection to do this kind of sharing, not the module system.
Several components of the sample inject the
There should be only one instance of the
UserService in the entire application
and only one provider of it.
UserService is an application-wide singleton.
You don't want each module to have its own separate instance.
Yet there is a real danger of that happening
SharedModule provides the
Do not specify app-wide singleton
providers in a shared module.
A lazy-loaded module that imports that shared module makes its own copy of the service.
The Core module
At the moment, the root folder is cluttered with the
TitleComponent that only appear in the root
You didn't include them in the
SharedModule for reasons just explained.
Instead, gather them in a single
CoreModule that you import once when the app starts
and never import anywhere else.
Perform the following steps:
- Create an
- Move the
- Create a
CoreModuleclass to own the core material.
- Update the
AppRootmodule to import
Most of this work is familiar. The interesting part is the
You're importing some extra symbols from the Angular core library that you're not using yet. They'll become relevant later in this page.
@NgModule metadata should be familiar.
You declare the
TitleComponent because this module owns it and you export it
AppComponent (which is in
AppModule) displays the title in its template.
TitleComponent needs the Angular
NgIf directive that you import from
CoreModule provides the
UserService. Angular registers that provider with the app root injector,
making a singleton instance of the
UserService available to any component that needs it,
whether that component is eagerly or lazily loaded.
This scenario is clearly contrived. The app is too small to worry about a single service file and a tiny, one-time component.
TitleComponent sitting in the root folder isn't bothering anyone.
AppModule can register the
as it does currently, even if you decide to relocate the
UserService file to the
Real-world apps have more to worry about.
They can have several single-use components (such as spinners, message toasts, and modal dialogs)
that appear only in the
You don't import them elsewhere so they're not shared in that sense.
Yet they're too big and messy to leave loose in the root folder.
Apps often have many singleton services like this sample's
Each must be registered exactly once, in the app root injector, when the application starts.
While many components inject such services in their constructors—and
import statements to import their symbols—no
other component or module should define or re-create the services themselves.
Their providers aren't shared.
We recommend collecting such single-use classes and hiding their details inside a
A simplified root
CoreModule in its capacity as orchestrator of the application as a whole.
Having refactored to a
CoreModule and a
SharedModule, it's time to clean up the other modules.
A trimmer AppModule
Here is the updated
AppModule paired with version 3 for comparison:
AppModule now has the following qualities:
- A little smaller because many
src/app/rootclasses have moved to other modules.
- Stable because you'll add future components and providers to other modules, not this one.
- Delegated to imported modules rather than doing work.
- Focused on its main task, orchestrating the app as a whole.
A trimmer ContactModule
Here is the new
ContactModule paired with the prior version:
Notice the following:
- The imports include
- The new version is leaner and cleaner.
Configure core services with CoreModule.forRoot
A module that adds providers to the application can offer a facility for configuring those providers as well.
By convention, the
forRoot static method both provides and configures services at the same time.
It takes a service configuration object and returns a
ModuleWithProviders, which is
a simple object with the following properties:
providers: the configured providers
AppModule imports the
CoreModule and adds the
providers to the
More precisely, Angular accumulates all imported providers before appending the items listed in
This sequence ensures that whatever you add explicitly to the
AppModule providers takes precedence
over the providers of imported modules.
CoreModule.forRoot method that configures the core
You've extended the core
UserService with an optional, injected
UserServiceConfig exists, the
UserService sets the user name from that config.
CoreModule.forRoot that takes a
Lastly, call it within the
imports list of the
The app displays "Miss Marple" as the user instead of the default "Sherlock Holmes".
forRoot only in the root application module,
Calling it in any other module, particularly in a lazy-loaded module,
is contrary to the intent and can produce a runtime error.
Remember to import the result; don't add it to any other
Prevent reimport of the CoreModule
Only the root
AppModule should import the
Bad things happen if a lazy-loaded module imports it.
You could hope that no developer makes that mistake.
Or you can guard against it and fail fast by adding the following
The constructor tells Angular to inject the
CoreModule into itself.
That seems dangerously circular.
The injection would be circular if Angular looked for
CoreModule in the current injector.
@SkipSelf decorator means "look for
CoreModule in an ancestor injector, above me in the injector hierarchy."
If the constructor executes as intended in the
there is no ancestor injector that could provide an instance of
The injector should give up.
By default, the injector throws an error when it can't find a requested provider.
@Optional decorator means not finding the service is OK.
The injector returns
parentModule parameter is null,
and the constructor concludes uneventfully.
It's a different story if you improperly import
CoreModule into a lazy-loaded module such as
HeroModule (try it).
Angular creates a lazy-loaded module with its own injector, a child of the root injector.
@SkipSelf causes Angular to look for a
CoreModule in the parent injector, which this time is the root injector.
Of course it finds the instance imported by the root
parentModule exists and the constructor throws the error.
You made it! You can examine and download the complete source for this final version from the live example.
Frequently asked questions
Now that you understand NgModules, you may be interested in the companion NgModule FAQs page with its ready answers to specific design and implementation questions.