An NgModule is a container that organizes related components, directives, pipes, and services into cohesive blocks of functionality. Every Angular application has at least one module — the root module. As applications grow, you split them into feature modules, shared modules, and routing modules to maintain clarity and enable lazy loading.
The root module is the entry point of the application. It bootstraps the root component and imports essential modules like BrowserModule and HttpClientModule.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
@NgModule({
declarations: [AppComponent], // Components, directives, pipes belonging to this module
imports: [BrowserModule, HttpClientModule, AppRoutingModule], // Other modules this module needs
providers: [], // Services available application-wide
bootstrap: [AppComponent] // Root component to bootstrap
})
export class AppModule { }
index.html host page (only in root module).Feature modules group related functionality for a specific feature area (e.g., Products, Orders, Admin). They help organize code into logical boundaries and enable lazy loading.
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { ProductListComponent } from './product-list.component';
import { ProductDetailComponent } from './product-detail.component';
import { ProductsRoutingModule } from './products-routing.module';
@NgModule({
declarations: [ProductListComponent, ProductDetailComponent],
imports: [CommonModule, FormsModule, ProductsRoutingModule],
exports: [ProductListComponent] // Optional: expose if used outside this module
})
export class ProductsModule { }
CommonModule instead of BrowserModule. BrowserModule should only be imported once — in the root module. CommonModule provides common directives like ngIf and ngFor.Shared modules contain commonly used components, directives, pipes, and pipes that multiple feature modules need. Create a shared module to declare and export reusable pieces.
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { HighlightDirective } from './highlight.directive';
import { TruncatePipe } from './truncate.pipe';
import { LoadingSpinnerComponent } from './loading-spinner.component';
@NgModule({
declarations: [HighlightDirective, TruncatePipe, LoadingSpinnerComponent],
imports: [CommonModule, FormsModule],
exports: [
HighlightDirective, // Custom directive
TruncatePipe, // Custom pipe
LoadingSpinnerComponent, // Custom component
CommonModule, // Re-export CommonModule so importing modules get ngIf/ngFor
FormsModule // Re-export FormsModule for template-driven forms
]
})
export class SharedModule { }
Feature modules then import SharedModule to access all the common pieces without duplicating declarations.
Routing modules separate routing configuration from the feature module itself. This follows Angular's recommended pattern and enables lazy loading easily.
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ProductListComponent } from './product-list.component';
import { ProductDetailComponent } from './product-detail.component';
import { AuthGuard } from '../core/auth.guard';
const routes: Routes = [
{ path: '', component: ProductListComponent },
{ path: ':id', component: ProductDetailComponent, canActivate: [AuthGuard] }
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ProductsRoutingModule { }
As your application scales, organize modules into layers:
providedIn: 'root' on services instead.import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { CoreModule } from './core/core.module';
import { SharedModule } from './shared/shared.module';
import { ProductsModule } from './products/products.module';
import { AppRoutingModule } from './app-routing.module';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
CoreModule, // Singleton services and app shell
SharedModule, // Common components, pipes, directives
ProductsModule, // Feature module (can be lazy-loaded in production)
AppRoutingModule // Root routing — should be last
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
You now understand Angular module architecture: the root module (AppModule), feature modules for organizing feature areas, shared modules for reusable declarations, and routing modules for route configuration. You also learned about NgModule metadata properties (declarations, imports, exports, providers, bootstrap) and best practices for structuring enterprise applications.
SharedModule that exports a HighlightDirective, a SortByPipe, and a ModalComponent. Create a CoreModule that provides an AuthService (singleton), an auth interceptor, and a HeaderComponent. Create a feature OrdersModule with its own routing module. Then refactor the AppModule to import CoreModule, SharedModule, and lazy-load OrdersModule.