Angular Standalone Components: migratie en best practices in 2026
Volledige gids voor het migreren van Angular-applicaties van NgModules naar standalone components. Behandelt de officiële CLI-migratie in 3 stappen, lazy loading, routing en best practices voor Angular 21.

Angular standalone components maken NgModules overbodig, verminderen boilerplate en maken fijnmazig lazy loading mogelijk in de hele applicatie. Sinds Angular 19 standalone tot standaard maakte en Angular 21 zoneless change detection consolideerde, is het migreren van legacy modulegebaseerde codebases zowel eenvoudig als impactvol geworden.
Het officiële Angular CLI-schematic regelt het grootste deel van de migratie automatisch in drie passes. Een typische enterprise-applicatie kan de conversie binnen één sprint afronden, waarbij bundlegroottes met 30-50 % dalen dankzij lazy loading per component.
NgModules vs standalone components: wat is er veranderd
NgModules dienden sinds Angular 2 als de compilatiecontext voor componenten. Elk component, elke directive en elke pipe moest in precies één module worden gedeclareerd, en gedeelde functionaliteit vereiste zorgvuldig georchestreerde module-imports en -exports. Dit leidde tot strakke koppeling tussen onafhankelijke features en bemoeilijkte tree-shaking.
Standalone components draaien dit model om. Elk component declareert zijn eigen afhankelijkheden direct in de imports-array van de @Component-decorator. Geen moduleregistratie, geen gedeelde modules, geen barrel-exports van de halve applicatie.
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HeroCardComponent } from './hero-card.component';
import { SearchPipe } from '../pipes/search.pipe';
@Component({
selector: 'app-hero-list',
standalone: true,
imports: [CommonModule, HeroCardComponent, SearchPipe],
template: `
<div class="hero-grid">
@for (hero of heroes | search:query; track hero.id) {
<app-hero-card [hero]="hero" />
}
</div>
`
})
export class HeroListComponent {
heroes = signal<Hero[]>([]);
query = signal('');
}De imports-array vervangt de volledige NgModule-afhankelijkheidsgraaf. De bundler ziet precies welke componenten, pipes en directives elk bestand nodig heeft, wat nauwkeurige tree-shaking mogelijk maakt.
Het CLI-migratieproces in 3 stappen
Angular biedt een geautomatiseerd schematic dat de migratie in drie opeenvolgende passes afhandelt. Elke stap bouwt voort op de vorige, en het project moet tussen elke pass schoon compileren.
Stap 1: declaraties omzetten naar standalone
De eerste pass scant elk component, elke directive en elke pipe in het project, voegt standalone: true toe en verplaatst de noodzakelijke imports vanuit de bovenliggende NgModule naar de eigen imports-array van elk component.
# Step 1: Convert all declarations to standalone
ng g @angular/core:standalone --path=src/appKies bij de prompt "Convert all components, directives and pipes to standalone". Het schematic gebruikt statische analyse om afhankelijkheden te resolven, dus elk component met metadata die niet bij build-time geanalyseerd kunnen worden, wordt overgeslagen met een waarschuwing.
Stap 2: onnodige NgModules verwijderen
Nu alle declaraties standalone zijn, worden veel NgModules lege schillen. Deze pass identificeert modules die alleen standalone-declaraties opnieuw exporteerden en verwijdert ze.
# Step 2: Remove empty NgModules
ng g @angular/core:standalone --path=src/appKies "Remove unnecessary NgModule classes". Modules die nog providers, route-configuraties bevatten of door meerdere andere modules worden geïmporteerd, blijven behouden met een TODO-commentaar voor handmatige review.
Stap 3: overschakelen naar standalone bootstrap
De laatste pass vervangt de root-NgModule door Angular's bootstrapApplication-API en zet het root-component om naar standalone.
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';
bootstrapApplication(AppComponent, appConfig)
.catch(err => console.error(err));import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { routes } from './app.routes';
import { authInterceptor } from './interceptors/auth.interceptor';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideHttpClient(withInterceptors([authInterceptor]))
]
};Het ApplicationConfig-patroon vervangt de providers- en imports-arrays van de root-module. Alle provider-functies (provideRouter, provideHttpClient, provideAnimations) werken direct zonder module-wrappers.
Routing-migratie: van modules naar loadComponent
Routing-modules vereisen handmatige aandacht omdat het schematic loadChildren-module-imports niet automatisch omzet naar loadComponent of route-niveau loadChildren met standalone-routes.
Het legacy-patroon laadde hele feature-modules:
const routes: Routes = [
{
path: 'dashboard',
loadChildren: () => import('./dashboard/dashboard.module')
.then(m => m.DashboardModule)
}
];Het standalone-equivalent laadt afzonderlijke componenten of routebestanden direct:
import { Routes } from '@angular/router';
export const routes: Routes = [
{
path: 'dashboard',
loadComponent: () => import('./dashboard/dashboard.component')
.then(c => c.DashboardComponent)
},
{
path: 'settings',
loadChildren: () => import('./settings/settings.routes')
.then(r => r.settingsRoutes)
}
];import { Routes } from '@angular/router';
export const settingsRoutes: Routes = [
{
path: '',
loadComponent: () => import('./settings.component')
.then(c => c.SettingsComponent),
children: [
{
path: 'profile',
loadComponent: () => import('./profile/profile.component')
.then(c => c.ProfileComponent)
},
{
path: 'security',
loadComponent: () => import('./security/security.component')
.then(c => c.SecurityComponent)
}
]
}
];loadComponent lazy-laadt een enkel component. loadChildren met een routebestand lazy-laadt een heel feature-gebied. Beide produceren losse chunks die de browser op aanvraag ophaalt.
Klaar om je Angular gesprekken te halen?
Oefen met onze interactieve simulatoren, flashcards en technische tests.
Omgaan met SharedModules en gemeenschappelijke afhankelijkheden
SharedModules — de allesomvattende modules die veelgebruikte componenten, directives en pipes exporteren — vormen de meest voorkomende blokkade tijdens de migratie. Het schematic kan ze niet automatisch verwijderen omdat meerdere modules ze importeren.
De oplossing: gedeelde declaraties één voor één omzetten naar standalone en daarna de SharedModule verwijderen zodra niets ze nog importeert.
// Before: SharedModule re-exports everything
@NgModule({
declarations: [LoadingSpinner, TooltipDirective, TruncatePipe],
exports: [LoadingSpinner, TooltipDirective, TruncatePipe],
imports: [CommonModule]
})
export class SharedModule {}
// After: Each declaration is standalone, import directly
// loading-spinner.component.ts
@Component({
selector: 'app-loading-spinner',
standalone: true,
template: `<div class="spinner" role="status"></div>`
})
export class LoadingSpinner {}Gebruikers importeren LoadingSpinner nu direct in plaats van de hele SharedModule. De bundler neemt alleen de specifieke componenten op die elke route nodig heeft.
Standalone-only ontwikkeling afdwingen
Na de migratie is het cruciaal te voorkomen dat nieuwe NgModules opnieuw in de codebase sluipen. Angular biedt hiervoor een TypeScript-compileroptie.
{
"angularCompilerOptions": {
"strictStandalone": true
}
}Met strictStandalone ingeschakeld levert elke poging om een niet-standalone component, directive of pipe te maken een compilatiefout op. Dit dwingt de nieuwe architectuur af binnen het hele team.
Performancewinst: bundlegrootte en lazy loading
Het voornaamste performance-voordeel van standalone components komt van granulair lazy loading. Met NgModules werkte lazy loading op moduleniveau — één component uit een module importeren trok elke declaratie mee die de module exporteerde. Standalone components doorbreken die koppeling.
Een real-world benchmark op een middelgrote enterprise-applicatie (200+ componenten) toonde:
| Metriek | NgModule-gebaseerd | Standalone | Verbetering | |--------|---------------|------------|-------------| | Initiële bundle | 485 KB | 218 KB | -55 % | | Grootste lazy chunk | 142 KB | 38 KB | -73 % | | Time to Interactive | 3,2 s | 1,8 s | -44 % | | Buildtijd (esbuild) | 12,4 s | 8,1 s | -35 % |
Deze cijfers komen voort uit het wegvallen van de overhead van module-resolutie en de mogelijkheid voor de bundler om ongebruikte exports op componentniveau te elimineren in plaats van op moduleniveau.
Standalone components testen
Unittests vereenvoudigen aanzienlijk met standalone components. De TestBed-configuratie vereist niet langer het importeren van hele modules om de afhankelijkheden van een component te bevredigen.
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HeroListComponent } from './hero-list.component';
import { HeroService } from '../services/hero.service';
describe('HeroListComponent', () => {
let fixture: ComponentFixture<HeroListComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HeroListComponent],
providers: [
{ provide: HeroService, useValue: { getHeroes: () => of([]) } }
]
}).compileComponents();
fixture = TestBed.createComponent(HeroListComponent);
});
it('should render hero cards', () => {
fixture.componentRef.setInput('heroes', mockHeroes);
fixture.detectChanges();
const cards = fixture.nativeElement.querySelectorAll('app-hero-card');
expect(cards.length).toBe(mockHeroes.length);
});
});Het component gaat direct de imports-array van TestBed.configureTestingModule in. Alle gedeclareerde afhankelijkheden zijn al opgelost via het eigen imports, dus extra module-imports zijn niet nodig.
Veelvoorkomende migratievalkuilen
Circulaire imports tussen standalone components. Wanneer component A component B importeert en B importeert A, gooit de TypeScript-compiler een fout vanwege circulaire afhankelijkheid. De oplossing: extraheer de gedeelde interface naar een apart bestand of gebruik forwardRef() als tijdelijke workaround terwijl de afhankelijkheidsketen wordt gerefactord.
Externe libraries die nog NgModules gebruiken. Veel libraries zijn naar standalone gemigreerd, maar sommige legacy-pakketten exporteren nog NgModules. Importeer die modules direct in de imports-array van het standalone component — Angular ondersteunt het mengen van standalone- en modulegebaseerde imports.
Ontbrekende providers na het verwijderen van AppModule. Services die voorheen werden geleverd in de providers-array van de root-module moeten verhuizen naar de ApplicationConfig in app.config.ts of providedIn: 'root' gebruiken in de @Injectable-decorator. Route-scoped services moeten de providers-array in de routeconfiguraties gebruiken.
Begin met oefenen!
Test je kennis met onze gespreksimulatoren en technische tests.
Conclusie
- Het officiële Angular CLI-schematic automatiseert 80-90 % van de migratie via drie opeenvolgende passes: declaraties omzetten, modules verwijderen, bootstrap omschakelen
- Routing-modules vereisen handmatige conversie van
loadChildrenmet NgModules naarloadComponentof standalone routebestanden - SharedModules zijn de voornaamste blokkade — zet elke gedeelde declaratie afzonderlijk om naar standalone en verwijder daarna de module
- Schakel
strictStandalonein tsconfig in om te voorkomen dat na de migratie nieuwe NgModules worden geïntroduceerd - Bundlegroottes dalen 30-55 % dankzij tree-shaking op componentniveau en granulair lazy loading met
loadComponent - Unittests vereenvoudigen drastisch — importeer het standalone component direct in
TestBedzonder moduleconfiguratie - De zoneless change detection van Angular 21 en signal-gebaseerde reactiviteit sluiten van nature aan op de standalone-architectuur voor maximale performance
Begin met oefenen!
Test je kennis met onze gespreksimulatoren en technische tests.
Tags
Delen
Gerelateerde artikelen

Angular 19 Zoneless: Performance en Change Detection zonder Zone.js
Technische gids over Zoneless Change Detection in Angular 19 en 20. Werking van Signal-gebaseerde reactiviteit, activering van provideZonelessChangeDetection, migratieproblemen met setTimeout en Reactive Forms, SSR zonder Zone.js en prestatiebenchmarks.

Top 25 Angular Sollicitatievragen: Complete Gids voor Succes
De 25 meest gestelde Angular sollicitatievragen in 2026. Uitgebreide antwoorden, codevoorbeelden en tips om de Angular developer-rol binnen te halen.

Angular 18: Signals en nieuwe features
Angular 18 Signals, zoneless change detection en de nieuwe signal-gebaseerde API's voor performantere applicaties.