← Back to Articles         
Components Declared Before Standalone Components

Components Declared Before Standalone Components

Published on 02 Oct 2026     7 min read Angular
Older Angular vs Modern Angular

1. How Were Components Declared Before Standalone Components?

What is component declaration?

Before standalone components, Angular applications were NgModule-based.

A component had to belong to an NgModule. Therefore, after creating a component, it was added to the module's:

declarations: []

For example:

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    ProductComponent
  ]
})
export class AppModule { }

The key idea was:

Components, directives, and pipes were declared inside an NgModule before they could participate in that module's templates.


Full Simple Sample — Before Standalone

Suppose we have:

AppComponent
   ↓
ProductComponent

The AppComponent wants to use:

<app-product></app-product>

product.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-product',
  template: `
    <h2>Product Component</h2>
    <p>Laptop - ₹50,000</p>
  `
})
export class ProductComponent {
}

Notice that there was no standalone configuration.


app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <h1>My Application</h1>

    <app-product></app-product>
  `
})
export class AppComponent {
}

AppComponent uses:

<app-product></app-product>

But AppComponent did not directly import ProductComponent.

Instead, both components were declared in an NgModule.


app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { ProductComponent } from './product.component';

@NgModule({

  declarations: [
    AppComponent,
    ProductComponent
  ],

  imports: [
    BrowserModule
  ],

  providers: [],

  bootstrap: [
    AppComponent
  ]

})
export class AppModule {
}

The important part is:

declarations: [
  AppComponent,
  ProductComponent
]

This tells Angular that these components belong to this NgModule.


How Did It Work?

AppModule
   │
   └── declarations
          │
          ├── AppComponent
          │
          └── ProductComponent

Because both belonged to the same module, AppComponent could use ProductComponent:

<app-product></app-product>

What About Components From Another Module?

Suppose we had:

ProductModule

containing:

ProductComponent

Then we might write:

@NgModule({

  declarations: [
    ProductComponent
  ],

  exports: [
    ProductComponent
  ]

})
export class ProductModule {
}

Another module could then import:

imports: [
  ProductModule
]

The relationship was:

ProductComponent
       ↓
declared in
       ↓
ProductModule
       ↓
exported from
       ↓
ProductModule
       ↓
imported by
       ↓
AppModule
       ↓
available to AppModule templates

This module-level indirection is one reason standalone components simplify dependency management.


Important Rule in Traditional Angular

A non-standalone component could normally be declared in only one NgModule.

For example, this was invalid:

@NgModule({
  declarations: [
    ProductComponent
  ]
})
export class AppModule { }

and also:

@NgModule({
  declarations: [
    ProductComponent
  ]
})
export class ProductModule { }

Angular would complain that ProductComponent was declared by multiple NgModules.


2. How Are Component Dependencies Handled With Standalone Components?

With standalone components, the component itself specifies the template dependencies it needs using:

imports: []

For example:

@Component({
  imports: [
    Product
  ]
})
export class App {
}

There is no need to put the component in an NgModule's:

declarations: []

Full Simple Standalone Example

Let's rewrite the previous application using modern standalone Angular.

product.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-product',

  template: `
    <h2>Product Component</h2>
    <p>Laptop - ₹50,000</p>
  `
})
export class Product {
}

In current Angular, components are standalone by default.


app.ts

import { Component } from '@angular/core';

import { Product } from './product';

@Component({
  selector: 'app-root',

  imports: [
    Product
  ],

  template: `
    <h1>My Application</h1>

    <app-product></app-product>
  `
})
export class App {
}

The important part is:

imports: [
  Product
]

Because the template uses:

<app-product></app-product>

the component imports Product directly.


Dependency Flow

Now the relationship is much simpler:

App
 │
 │ imports
 ↓
Product

Instead of:

AppComponent
     ↓
AppModule
     ↓
ProductModule
     ↓
ProductComponent

Standalone Components Can Import Other Components

For example:

@Component({
  imports: [
    Header,
    ProductList,
    Footer
  ]
})
export class App {
}

The template can then use:

<app-header></app-header>

<app-product-list></app-product-list>

<app-footer></app-footer>

The dependencies are visible directly from the component.


Standalone Components Can Import Directives

Suppose we use:

<a routerLink="/products">Products</a>

We can import RouterLink:

import { Component } from '@angular/core';
import { RouterLink } from '@angular/router';

@Component({
  selector: 'app-menu',

  imports: [
    RouterLink
  ],

  template: `
    <a routerLink="/">Home</a>
    <a routerLink="/products">Products</a>
  `
})
export class Menu {
}

So:

Template uses
routerLink
    ↓
Component imports
RouterLink

Standalone Components Can Import Pipes

Suppose the component uses:

{{ productName | uppercase }}

Then:

import { Component } from '@angular/core';
import { UpperCasePipe } from '@angular/common';

@Component({
  selector: 'app-product',

  imports: [
    UpperCasePipe
  ],

  template: `
    <h2>{{ productName | uppercase }}</h2>
  `
})
export class Product {

  productName = 'laptop';

}

Dependency:

Template
   ↓
uppercase
   ↓
UpperCasePipe
   ↓
imports: [UpperCasePipe]

Standalone Components Can Import Other Standalone Dependencies

A realistic component might look like:

import { Component } from '@angular/core';
import { RouterLink } from '@angular/router';
import { CurrencyPipe } from '@angular/common';

import { ProductCard } from './product-card';

@Component({
  selector: 'app-products',

  imports: [
    RouterLink,
    CurrencyPipe,
    ProductCard
  ],

  template: `
    <h2>Products</h2>

    <p>{{ price | currency:'INR' }}</p>

    <app-product-card></app-product-card>

    <a routerLink="/">Back to Home</a>
  `
})
export class Products {

  price = 50000;

}

Here the component has three template dependencies:

Products
   │
   ├── RouterLink
   │
   ├── CurrencyPipe
   │
   └── ProductCard

All are visible directly in:

imports: [
  RouterLink,
  CurrencyPipe,
  ProductCard
]

What About Services?

This is an important distinction.

Not every dependency goes into:

imports: []

imports is primarily for template dependencies, such as:

  • Components
  • Directives
  • Pipes
  • Compatible NgModules when needed

Services are obtained through dependency injection.

For example:

import { Component, inject } from '@angular/core';
import { ProductService } from './product.service';

@Component({
  selector: 'app-products',

  template: `
    <h2>Products</h2>
  `
})
export class Products {

  private productService = inject(ProductService);

}

If the service has:

@Injectable({
  providedIn: 'root'
})
export class ProductService {
}

you don't put it in:

imports: []

So remember:

Component / Directive / Pipe
        ↓
      imports


Service
        ↓
Dependency Injection

Before vs Now

Before standalone Standalone Angular
Component declared in NgModule No NgModule declaration required
declarations: [] Not needed
NgModules controlled template scope Component imports declares template dependencies
Often import another NgModule Can directly import components/directives/pipes
AppModule commonly required Root AppModule not required
Module-centric Component-centric

Easy Example to Remember

Before

If AppComponent needs ProductComponent:

AppComponent
      │
      ↓
   AppModule
      ↑
      │
ProductComponent

Both were typically declared in:

declarations: [
  AppComponent,
  ProductComponent
]

Now

App
 │
 │ imports
 ↓
Product

Code:

@Component({
  imports: [
    Product
  ]
})
export class App {
}

This is the fundamental standalone model.


Key Points

Before standalone components

Components were declared inside an NgModule:

@NgModule({
  declarations: [
    AppComponent,
    ProductComponent
  ]
})
export class AppModule {
}

The declarations array contained the module's components, directives and pipes.


With standalone components

The component directly imports the template dependencies it needs:

@Component({
  imports: [
    Product,
    RouterLink,
    CurrencyPipe
  ]
})
export class App {
}

No:

declarations: []

is required.

Very important distinction

Template dependency
(Component / Directive / Pipe)
            ↓
        imports: []


Service dependency
            ↓
    Dependency Injection
    inject() / constructor

Interview Questions and Answers

1. How were components declared before standalone components?

Components were declared inside an Angular NgModule using the declarations array.

@NgModule({
  declarations: [
    AppComponent,
    ProductComponent
  ]
})
export class AppModule { }

2. What was the purpose of declarations?

declarations registered the components, directives, and pipes that belonged to an NgModule.

declarations: [
  ProductComponent
]

3. Can a traditional component be declared in multiple NgModules?

No. A non-standalone component should belong to only one NgModule's declarations.

If other modules needed it, its owning module could export it.


4. How are dependencies handled with standalone components?

Standalone components directly list their template dependencies in their own imports array.

@Component({
  imports: [
    Product,
    RouterLink
  ]
})
export class App { }

5. Do standalone components use declarations?

No.

Standalone components don't need to be declared in an NgModule.


6. If one standalone component uses another component, what should we do?

Import the child component into the parent:

@Component({
  imports: [
    Product
  ]
})
export class App { }

Then:

<app-product></app-product>

7. Do services go into the component's imports array?

No. Services are normally provided through Angular's dependency-injection system.

For example:

private productService = inject(ProductService);

with:

@Injectable({
  providedIn: 'root'
})

8. What can a standalone component's imports contain?

It can include template dependencies such as:

imports: [
  ProductCard,    // Component
  RouterLink,     // Directive
  CurrencyPipe    // Pipe
]

It can also interoperate with compatible NgModules when necessary.


9. What is the main architectural difference?

Before:

Component
   ↓
NgModule
   ↓
Other dependencies

Standalone:

Component
   ↓
Directly imports its template dependencies

Interview Quick Answer

Before standalone Angular, components, directives, and pipes were declared in an NgModule's declarations array, and NgModules established their template scope. With standalone components, each component directly declares the components, directives, and pipes its template needs through its imports array, while services continue to be handled through dependency injection.

← Back to Articles