Table of Contents

Among the upcoming features in Angular is the introduction of "Standalone Components" (SC), also referred to as "Optional NgModules". This feature will make the inclusion of NgModules no longer a requirement.

Numerous publications have covered SC. What's less frequently examined, though, is the question this piece sets out to answer: what consequences will SC bring for the modularity of an Angular application?

The term module is embedded in NgModule. With SC making NgModules optional — and potentially deprecated further down the line — does that signal the end of modules altogether? Given Angular's position as enterprise-grade and the core team's dedication to stability, such a shift would be quite surprising.

I'll begin with a brief run-through of SC and their benefits. Following that, I'll address the core issue — whether opting out of NgModules conflicts with modularity. To close, I'll discuss the most effective approaches to get ready for SC today.

The code for this piece can be found on

For those who'd rather watch than read, a video walkthrough is available:

1. What are Standalone Components?

The community has been buzzing about SC for months. One of Angular's principal developers, Igor Minar, mentioned that he'd been thinking about tackling NgModules since the early beta days of Angular — back in 2016. It was therefore a notable moment when Pawel Kozlowski published the official RFC for Standalone Components on GitHub.

Components sit at the heart of Angular. Each one currently requires an NgModule to supply its dependencies. This connection is set up via the declarations property within an NgModule's decorator.

As an example, a component needing the formGroup directive gets it from the NgModule through the ReactiveFormsModule import.

This principle applies equally to Pipes and Directives, the other visual primitives. For simplicity, when I refer to components here, I'm including those other two types as well.

This isn't merely redundant complexity. With the extra Component-Module link and the capacity of a single NgModule to declare many components, identifying exactly which dependencies a given component has becomes a non-trivial task.

NgModule declaring multiple Components

On top of components, there are Services — and a trio of ways to provide them. The provider can be the NgModule itself, the component, or the service can use the providedIn property to provide itself. This final approach has been the favored one since its arrival in Angular 6.

This shows that even a modest component with a form and a service brings a fair amount of intricacy.

Component with NgModule and Service

Standalone Components strip away that NgModule layer.

The component's own decorator will gain the necessary properties to do this. Service provisioning also becomes streamlined, leaving just two potential paths.

Standalone Component

2. How to modularise in Standalone Components?

Have NgModules been the source of modularity in Angular apps? If that's the case, should we be building modularly from here on?

2.1 What is a module?

A sensible way to think of a module is as a cohesive cluster of application elements. What binds them could vary — it might be a collection of presentation-only components, everything tied to an NgRx feature slice, or some other shared characteristic.

The defining trait of a module is that it can hide its internals. This encapsulation is what supports a reliable architecture, stopping any random part of the app from reaching into another.

2.2 Is NgModule a module?

Does the NgModule measure up to that definition? Regrettably, it only half-heartedly does. For one, it attempts to encapsulate the visual classes (Component, Directive, Pipes), but the enforcement is not there. In principle, I could write a component that extends another, non-exported component, give it a fresh selector, and there I've got direct access.

When it comes to Services, the story is even weaker. They can simply reside outside of any NgModule’s control.

Because NgModules can't guarantee real modularity, the central question here is already resolved:

Standalone Components, or Optional Modules, will leave an application's modularity untouched.

That, however, raises a different issue: what mechanism *should* we have been relying on for modular structure all along?

2.3 How to implement modules in Angular?

There's another construct in Angular that truly fits the bill. It's the library (or "lib"). The Angular CLI has been capable of generating libraries since version 6.

A library gets its own separate folder alongside the main app. It also typically has a barrel file, index.ts, where the boundary is established. Whatever that file exports is the library's public face. This can encompass Services, TypeScript Interfaces, functions, and yes, even NgModules.

As a worthwhile aside on NgModules within libraries: until SC arrive, you still need NgModules to expose components. So libraries will continue to contain them.

On the matter of forcibly maintaining encapsulation, it all comes down to developer discipline when importing. A modern IDE makes it quite easy to accidentally import a non-public file from inside a library. A tell-tale sign of this is when a relative path is used for the internal import, as opposed to the library's name for public ones.

Linting errors due to deep-import

Unfortunately, the standard Angular CLI offers no safeguards here. That's where nx comes into the picture. Acting as a CLI extension, nx provides a host of features, among them a linting rule aimed at modularity. This rule soundly rejects any attempt at what's called a "deep import" — the act of reaching directly into an unexported file. An in-depth article on this is linked above.

Nx also offers another linting rule to establish dependency relationships between modules. You can dictate, for instance, that module A may use modules B and C, but module B is only allowed to use C. These constraints are also checked via linting.

So it's the library pattern, along with nx, that genuinely satisfies the requirements of a module — not the NgModule.

3. How do I prepare best for the migration?

While SC aren't here yet, can we lay the groundwork now for an easy transition?

The community has favored a pattern for a while now — predating SC — called Single Component Angular Module (SCAM). By this design, each NgModule contains just one component.

If SCAM is already your practice, switching to SC will likely be a rudimentary matter of moving the imports and providers up into the @Component decorator. A script can handle this shift automatically. More details are available here.

Should you retroactively apply SCAM to a current project? If you have a substantial application and a strong urge for a speedy SC migration, then yes. Generally speaking, waiting for the official SC release is the safer bet.

A shim also provides SC right now. Keep in mind this shim is for exploratory purposes only and shouldn't be used in a production environment.

4. Summary

Angular offers a variety of pathways for dependency management. While flexible, this can also lead to inconsistency, especially for those starting fresh. The NgModule tends to add quite a bit of boilerplate. Its eventual elimination through Standalone (or Optional) Components represents a clear win.

Optional NgModules won't meaningfully change how libraries facilitate modularity. For applications built around the SCAM principle, a scripted migration will do the job. Without that pattern, you'll be doing the changes by hand.


My thanks go to Pawel Kozlowski for his careful review and feedback on this article.

6. Additional Resources