Angular Modules and Pipes
Angular Modules and Pipes Interview with follow-up questions
1. What is an Angular module and what is its purpose?
An Angular module (@NgModule) is a container that groups related components, directives, and pipes (its declarations), pulls in other modules (imports), registers providers, and exposes pieces via exports. Its purpose was to give those declarables a compilation context and organize the app into cohesive, lazy-loadable units.
The essential 2026 framing: NgModules are now optional/legacy. Since Angular 17, standalone components are the default, and they declare their own imports directly — so the module is no longer the unit of organization. New apps bootstrap with bootstrapApplication() and configure app-wide providers in an ApplicationConfig, not an AppModule.
So a current answer says: "An NgModule groups and provides a compilation context for declarables, but modern Angular favors standalone components and rarely needs NgModules — they remain only for backward compatibility and incremental migration." Mentioning that you'd build new features standalone signals up-to-date knowledge.
Follow-up 1
Can you explain how Angular modules are declared?
Angular modules are declared using the @NgModule decorator. The @NgModule decorator is applied to a class that represents the module. It takes an object as an argument, which contains various properties to configure the module. These properties include:
declarations: This property is used to declare the components, directives, and pipes that belong to the module.imports: This property is used to import other modules that are required by the module.exports: This property is used to export components, directives, and pipes from the module, making them available for other modules to use.providers: This property is used to provide services that are available within the module.bootstrap: This property is used to specify the root component of the module, which will be bootstrapped when the module is loaded.
Follow-up 2
What is the significance of the bootstrap array in an Angular module?
The bootstrap array in an Angular module is used to specify the root component of the module. This root component is the starting point of the application and will be bootstrapped when the module is loaded. Only the root module of an Angular application should have a bootstrap array, as it defines the entry point of the application. Other modules should not have a bootstrap array.
Follow-up 3
How does Angular handle multiple modules?
Angular handles multiple modules by using the concept of dependency injection. Each module can import other modules that it depends on using the imports property. This allows the components, directives, and services from the imported modules to be used within the importing module. Angular also provides a hierarchical structure for modules, where there is a root module and child modules. The root module is typically responsible for bootstrapping the application, while child modules can be used to organize and modularize different parts of the application.
Follow-up 4
What is the difference between a feature module and a root module?
A feature module is a module that is used to group related components, directives, pipes, and services together for a specific feature or functionality of an application. It is typically used to organize and modularize different parts of the application. On the other hand, a root module is the main module of an Angular application and is responsible for bootstrapping the application. It is the entry point of the application and defines the root component that will be loaded when the application starts. While a feature module can be imported into the root module, the root module should not be imported into any other module.
2. What is a pipe in Angular and what are its uses?
A pipe transforms a value for display in the template, using the | syntax, without mutating the source data. They keep formatting logic out of the component:
<p>{{ amount | currency:'USD' }}</p>
<p>{{ created | date:'mediumDate' }}</p>
<p>{{ user$ | async }}</p>
Uses: formatting (dates, currency, numbers, percent), text casing, slicing, JSON debugging, and subscribing to async values via async.
The points interviewers probe: pipes are pure by default, meaning they re-run only when their input reference changes — which is great for performance but is why a "filter list" pipe often won't update on in-place mutation (mark it pure: false, or better, filter in the component). In modern Angular custom pipes are standalone (add them to a component's imports), and the async pipe is especially valuable because it auto-subscribes/unsubscribes and works cleanly with OnPush and zoneless change detection. A current note: for derived display values you can also use a computed() signal instead of a custom pipe.
Follow-up 1
Can you explain how to create a custom pipe in Angular?
To create a custom pipe in Angular, you need to follow these steps:
- Create a new TypeScript file for your pipe, for example
my-custom-pipe.ts. - Import the
PipeandPipeTransforminterfaces from@angular/core. - Decorate your class with the
@Pipedecorator, providing a name for your pipe. - Implement the
PipeTransforminterface in your class and define thetransformmethod. - Use the
transformmethod to define the logic for transforming the input data. - Export your pipe class so that it can be used in other parts of your application.
Here's an example of a custom pipe that converts a string to uppercase:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'uppercase'
})
export class UppercasePipe implements PipeTransform {
transform(value: string): string {
return value.toUpperCase();
}
}
You can then use this custom pipe in your templates like this: {{ myString | uppercase }}.
Follow-up 2
What is a pure pipe and an impure pipe?
In Angular, a pure pipe is a pipe that is stateless and does not depend on any external factors. It means that the output of a pure pipe is only determined by its input. Pure pipes are highly efficient and Angular optimizes their execution by caching the result until the input changes.
On the other hand, an impure pipe is a pipe that can have side effects and depends on external factors. Impure pipes are re-evaluated on every change detection cycle, even if the input has not changed. They are less efficient compared to pure pipes.
To specify whether a pipe is pure or impure, you can set the pure property in the @Pipe decorator. By default, pipes are pure unless specified otherwise.
Follow-up 3
How can you use pipes in Angular templates?
In Angular templates, you can use pipes by using the | symbol followed by the name of the pipe. The pipe is applied to the expression that precedes it, and the transformed value is displayed in the template.
Here's an example of using the uppercase pipe to convert a string to uppercase:
<p>{{ myString | uppercase }}</p>
You can also chain multiple pipes together to perform multiple transformations. For example:
<p>{{ myString | uppercase | slice:0:10 }}</p>
In this example, the uppercase pipe is applied first to convert the string to uppercase, and then the slice pipe is applied to get the first 10 characters of the transformed string.
Follow-up 4
What is the pipe transform method and what does it do?
The transform method is a method defined in the PipeTransform interface that needs to be implemented when creating a custom pipe in Angular. This method is responsible for transforming the input data.
The transform method takes the input value as an argument and can also accept additional arguments if needed. It performs the necessary logic to transform the input value and returns the transformed result.
Here's an example of the transform method in a custom pipe:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'myCustomPipe'
})
export class MyCustomPipe implements PipeTransform {
transform(value: any, arg1: any, arg2: any): any {
// Perform transformation logic
return transformedValue;
}
}
In this example, the transform method takes the value argument as the input value and arg1 and arg2 as additional arguments. It performs the necessary logic to transform the value and returns the transformed result.
3. How can Angular modules help in organizing an application?
Historically, NgModules organized an app by grouping related declarables into feature modules (a UserModule, an AdminModule), with a SharedModule for common UI and a CoreModule for singletons — which encapsulated features, encouraged reuse, and enabled route-level lazy loading of whole modules.
The modern reality interviewers expect you to acknowledge: with standalone components the default since v17, you typically organize by feature folders of standalone components rather than NgModules. Each component imports exactly what it needs, lazy loading is done per-route with loadComponent (or loadChildren pointing at a routes file), and shared UI is just standalone components/directives you import where needed.
{ path: 'admin', loadChildren: () => import('./admin/admin.routes').then(m => m.ADMIN_ROUTES) }
So a current answer is: "NgModules could organize an app and still can, but modern Angular achieves the same modularity — encapsulation, reuse, lazy loading — with standalone components and route-based code splitting, without the module boilerplate."
Follow-up 1
What is the role of the declarations array in an Angular module?
The declarations array in an Angular module is used to specify the components, directives, and pipes that belong to that module. These declarations are then available for use within the module and its components. By declaring the components, directives, and pipes in the module, Angular knows how to compile and render them when they are used in the templates of the module's components.
Follow-up 2
How can you import and export components, directives, and pipes using Angular modules?
Components, directives, and pipes can be imported and exported using the imports and exports arrays in an Angular module. The imports array is used to import other modules, while the exports array is used to export components, directives, and pipes from the current module. By exporting these elements, they become available for use in other modules that import the current module.
Follow-up 3
What is the difference between eager loading and lazy loading of modules?
Eager loading and lazy loading are two different strategies for loading modules in an Angular application. Eager loading refers to loading a module and all its dependencies upfront when the application starts. This means that all the code for the module is downloaded and executed immediately. On the other hand, lazy loading refers to loading a module and its dependencies only when they are actually needed. This can help in reducing the initial load time of the application and improving performance.
Follow-up 4
Can you explain the concept of shared modules in Angular?
Shared modules in Angular are modules that contain components, directives, and pipes that are shared across multiple other modules in an application. These modules are typically used to encapsulate and share common functionality, such as UI components, services, or utility functions. By creating shared modules, developers can avoid duplicating code and ensure consistency across different parts of the application. Shared modules can be imported and used by other modules that require the shared functionality.
4. What are some of the built-in pipes provided by Angular?
Common built-in pipes (from @angular/common):
DatePipe—{{ d | date:'medium' }}formats dates.CurrencyPipe—{{ p | currency:'USD' }}formats money.DecimalPipe(number) andPercentPipe— numeric/percent formatting.UpperCasePipe/LowerCasePipe/TitleCasePipe— text casing.SlicePipe— subset of an array/string.JsonPipe— stringify an object (handy for debugging).KeyValuePipe— iterate an object/Map's entries.AsyncPipe— subscribe to an Observable/Promise and auto-update (and auto-unsubscribe).
A current note worth adding: with standalone components you import the specific pipes you use (e.g. DatePipe) or CommonModule; the async pipe is the standout because it manages subscriptions for you and pairs perfectly with OnPush/zoneless change detection. The number/date/currency pipes are also locale-aware — register locale data for non-default locales.
Follow-up 1
How can you use the date pipe in Angular?
The date pipe in Angular is used to format dates. It accepts a date value and a format string as parameters. The format string can include various placeholders to represent different parts of the date, such as year, month, day, hour, minute, etc. Here is an example of how to use the date pipe:
<p>{{ myDate | date:'dd/MM/yyyy' }}</p>
This will display the value of myDate in the format 'dd/MM/yyyy'.
Follow-up 2
What is the purpose of the currency pipe?
The currency pipe in Angular is used to format currency values. It accepts a number value and a currency code as parameters. The currency code is optional and defaults to the currency of the current locale. Here is an example of how to use the currency pipe:
<p>{{ price | currency:'USD' }}</p>
This will display the value of price in the format of the specified currency code (USD in this case).
Follow-up 3
Can you explain how the percent pipe works?
The percent pipe in Angular is used to format percentages. It accepts a number value and an optional digitInfo parameter as parameters. The digitInfo parameter is used to specify the number of decimal places and other formatting options. Here is an example of how to use the percent pipe:
<p>{{ ratio | percent:'1.2-2' }}</p>
This will display the value of ratio as a percentage with two decimal places and a minimum of one integer digit.
Follow-up 4
What is the role of the async pipe in Angular?
The async pipe in Angular is used to subscribe to an Observable or Promise and automatically update the view when the data changes. It eliminates the need to manually subscribe and unsubscribe from the Observable or Promise. Here is an example of how to use the async pipe:
<p>{{ data$ | async }}</p>
This will automatically update the view whenever the data emitted by the Observable data$ changes.
5. How can you handle module loading in Angular?
"Module loading" in modern Angular is mostly about lazy loading via the Router. Eager dependencies are pulled in through a standalone component's imports (or, legacy, an NgModule's imports array), but the performance-relevant part is code splitting routes so bundles load on demand:
export const routes: Routes = [
// lazy-load a standalone component
{ path: 'profile', loadComponent: () => import('./profile.component').then(m => m.ProfileComponent) },
// lazy-load a set of routes
{ path: 'admin', loadChildren: () => import('./admin.routes').then(m => m.ADMIN_ROUTES) },
];
The current framing: the old approach used loadChildren pointing at a lazy NgModule; today you use loadComponent for standalone components and loadChildren for a routes array. You can tune this with route preloading strategies (withPreloading(PreloadAllModules) or a custom strategy) to fetch lazy bundles in the background after initial load. For in-view deferral, the @defer block lazy-loads parts of a template on a trigger (viewport, interaction, idle).
Follow-up 1
What is the role of the imports array in an Angular module?
The imports array in an Angular module is used to import other modules into the current module. By importing a module, you can access its components, directives, and services in the current module. This allows you to organize your code into reusable and modular pieces. The imports array is also used to load external libraries and modules that your application depends on.
Follow-up 2
Can you explain the concept of lazy loading in Angular?
Lazy loading is a concept in Angular that allows you to load modules on-demand, instead of loading them all at once when the application starts. This can improve the initial loading time of your application, as only the necessary modules are loaded when they are actually needed. To implement lazy loading, you need to define a separate routing module for the lazy-loaded module and configure the routes accordingly. When a user navigates to a route that requires a lazy-loaded module, Angular will load the module and render the corresponding components.
Follow-up 3
How can you pre-load modules in Angular?
In Angular, you can pre-load modules to improve the performance of your application. Pre-loading modules means that the modules are loaded in the background while the user is interacting with the application, so that they are available instantly when needed. To pre-load modules, you can use the PreloadAllModules strategy provided by the RouterModule. You can configure this strategy in the AppRoutingModule by importing the RouterModule and calling the forRoot() method with the PreloadAllModules strategy.
Follow-up 4
What is the difference between forRoot() and forChild() methods in Angular?
The forRoot() and forChild() methods are used when configuring routes in Angular. The main difference between these two methods is that forRoot() is used in the root AppRoutingModule, while forChild() is used in feature modules. The forRoot() method should only be called once in the root AppRoutingModule, and it sets up the router configuration for the entire application. On the other hand, the forChild() method is used in feature modules to configure additional routes specific to that module. Calling forChild() multiple times in different feature modules will merge the route configurations together.
Live mock interview
Mock interview: Angular Modules and Pipes
- Read your scene and goals
- Talk it out; goals tick off live
- Get a score and stronger lines
Your voice and your AI key never touch our servers; the key stays in this browser and is sent only to Google. Only your round scores are saved to track progress.