Angular course · Module 3: Modules

NgModules - The Clan System

3 min read ·
In this lesson4

In feudal Japan, each clan (han) had its own structure, territory, and resources. In Angular, modules play a similar role - they group related elements and define their scope.

What are NgModules?

NgModules are organizational containers in Angular. Although Standalone Components have been preferred since Angular 17+, knowledge of modules is crucial for:

  • Working with legacy projects
  • Understanding Angular architecture
  • Lazy loading (still popular with modules)

Anatomy of an NgModule

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';

// Components of this module
import { SamuraiListComponent } from './samurai-list.component';
import { SamuraiCardComponent } from './samurai-card.component';
import { SamuraiDetailComponent } from './samurai-detail.component';

// Services
import { SamuraiService } from './samurai.service';

@NgModule({
  // Components, directives, pipes BELONGING to this module
  declarations: [
    SamuraiListComponent,
    SamuraiCardComponent,
    SamuraiDetailComponent
  ],

  // Other modules we NEED
  imports: [
    CommonModule,  // *ngIf, *ngFor, async pipe, etc.
    FormsModule    // ngModel, template-driven forms
  ],

  // Elements SHARED with other modules
  exports: [
    SamuraiListComponent,
    SamuraiCardComponent
  ],

  // Services available in this module (legacy approach)
  providers: [
    SamuraiService
  ]
})
export class SamuraiModule { }

A note for Angular 19 and later: components are standalone by default, and such a component cannot be listed in declarations - the compiler reports error NG6008. A component that belongs to an NgModule needs standalone: false in its decorator; a standalone component is added to a module through imports.

@NgModule Decorator Properties

PropertyDescriptionExample
declarationsComponents, directives, pipes belonging to the module[MyComponent, MyDirective]
importsModules we need[CommonModule, FormsModule]
exportsElements shared externally[MyComponent]
providersServices (legacy, better to use providedIn)[MyService]
bootstrapMain component (only AppModule)[AppComponent]

AppModule - The Central Castle

// app.module.ts - main application module
@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,      // Required for browser applications
    AppRoutingModule,   // Routing
    SamuraiModule,      // Our feature module
    DojoModule
  ],
  providers: [],
  bootstrap: [AppComponent]  // Startup component
})
export class AppModule { }

Picture a module as a clan - declarations are the warriors who belong to it, imports are the alliances it depends on, exports are the forces it lends to others - and AppModule, with its bootstrap field, is the castle from which the whole application marches out.

Code for this lesson: src/app/app.component.ts
import { Component } from '@angular/core';
import { SamuraiModule } from './samurai/samurai.module';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [SamuraiModule],
  template: `
    <div class="dojo">
      <header>
        <h1>Clans and Provinces</h1>
        <p>Module 3: Code Organization in Angular</p>
      </header>

      <main>
        <section class="info-panel">
          <h2>Module Structure</h2>
          <p>Clans (modules) organize warriors (components) into logical groups.</p>
          <ul>
            <li>Feature Modules - functionalities</li>
            <li>Shared Modules - shared elements</li>
            <li>Core Module - singleton services</li>
          </ul>
        </section>

        <section class="demo-panel">
          <h2>Samurai Clan (Feature Module)</h2>
          <app-samurai-list></app-samurai-list>
        </section>
      </main>
    </div>
  `,
  styles: [`
    .dojo {
      font-family: 'Segoe UI', sans-serif;
      max-width: 900px;
      margin: 0 auto;
      padding: 20px;
      background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
      min-height: 100vh;
      color: #eee;
    }
    header {
      text-align: center;
      border-bottom: 2px solid #c9a227;
      padding-bottom: 20px;
    }
    h1 { color: #c9a227; }
    h2 { color: #c9a227; }
    .info-panel, .demo-panel {
      background: rgba(255,255,255,0.05);
      border: 1px solid #c9a227;
      border-radius: 8px;
      padding: 20px;
      margin: 20px 0;
    }
    ul { list-style: none; padding: 0; }
    li::before { content: "» "; }
  `]
})
export class AppComponent {}

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. What do we put in the 'declarations' property of the @NgModule decorator?

  2. 2. Which @NgModule property points to the application's main startup component and appears only in AppModule?

These are 2 of 5 questions for this lesson. Solve the rest in the game.

Hands-on tasks in the game

  • Horizontal ordering

    Arrange the tokens of a single import line for the NgModule decorator from @angular/core:

  • Code editor

    Complete the @NgModule decorator for the SamuraiModule module with the SamuraiListComponent and SamuraiCardComponent components.

  • Click in order

    Click the elements in order to build the start of the decorator: @NgModule({

  • Vertical ordering

    Order the properties inside the @NgModule decorator according to the typical layout (consecutive lines from top):

Useful articles