Many components, directives, and pipes are genuinely useful across several unrelated features, buttons, form fields, date formatting. This lesson covers the shared module pattern and its modern standalone equivalent.
What Is a Shared Module?
In NgModule-based Angular, a "shared module" is a module that declares and exports common, reusable building blocks, so any feature module can import it once and get access to everything it exports, rather than each feature reimplementing the same button or pipe.
In standalone-component Angular, the same idea exists without a formal SharedModule class: reusable components/directives/pipes are simply standalone, and any component that needs one imports it directly.
The standalone version needs no shared module at all, each consumer imports exactly what it uses.
Organizing Reusable Building Blocks
// classic: one shared module, imported everywhere
imports: [SharedModule]
// standalone: import specific pieces directly
imports: [ButtonComponent, IconComponent, TruncatePipe]
Classic shared modules bundle multiple reusable exports behind a single imports: [SharedModule] line.
Standalone components skip the bundling step, consumers import exactly what they need, and nothing more.
Barrel files (an index.ts re-exporting multiple standalone pieces) can still simplify import statements without creating an actual NgModule.
Both approaches aim for the same goal: avoid re-implementing the same reusable UI piece in multiple features.
Shared Building Blocks Cheatsheet
Comparing the classic and modern approaches to sharing reusable pieces.
Aspect
Classic SharedModule
Standalone Equivalent
Declaring reusable pieces
declarations + exports
Just mark each piece standalone: true
Consuming them
imports: [SharedModule]
imports: [SpecificComponent, SpecificPipe]
Bundle impact
Whole module's exports available, whether used or not
Only what's explicitly imported is included
Discoverability
One module to browse for available pieces
Barrel index.ts files can serve a similar purpose
Why the Shared Module Pattern Existed
Before standalone components, every component had to belong to exactly one NgModule. Re-declaring the same ButtonComponent in multiple feature modules was not allowed, so a dedicated shared module, imported by every feature that needed those common pieces, became the standard workaround.
The Standalone Equivalent: Just Import What You Need
With standalone components, there's no declaration conflict to work around, any component can simply import any other standalone component, directive, or pipe directly. This removes the shared module layer entirely while keeping the same reuse benefit.
While not strictly necessary, a barrel index.ts re-exporting several related standalone pieces from a shared UI folder can make imports slightly tidier, without recreating NgModule-style coupling.
// shared/ui/index.ts
export * from './button.component';
export * from './icon.component';
// consumer
import { ButtonComponent, IconComponent } from '../shared/ui';
Common Mistakes
Recreating a monolithic SharedModule-style barrel that re-exports far more than a given component actually needs, working against tree-shaking.
Declaring the same reusable component in multiple NgModules in a legacy codebase, which Angular does not allow.
Forgetting that standalone components need direct imports; there's no implicit "shared module" providing them automatically.
Mixing classic shared modules and ad hoc standalone imports inconsistently across a codebase without a clear convention.
Key Takeaways
Shared modules bundled common, reusable components/directives/pipes for classic NgModule-based Angular.
Standalone components remove the need for a dedicated shared module, consumers import exactly what they use.
Barrel index.ts files can still simplify imports for a folder of related standalone pieces.
Both approaches serve the same underlying goal: avoid duplicating common UI building blocks across features.
Pro Tip
In a standalone-component codebase, organize reusable pieces (buttons, form fields, icons) into a clearly named shared/ui folder with a barrel index.ts; it keeps the discoverability benefit of a shared module without any of the NgModule boilerplate.
You now understand the shared module pattern and its standalone equivalent. Next, learn about Feature Modules for organizing a large application by domain.