Angular Standalone Components: Migration und Best Practices in 2026
Vollständiger Leitfaden zur Migration von Angular-Anwendungen von NgModules zu Standalone-Komponenten. Behandelt die offizielle 3-stufige CLI-Migration, Lazy Loading, Routing und Best Practices für Angular 21.

Angular Standalone Components machen NgModules überflüssig, reduzieren Boilerplate-Code und ermöglichen feingranulares Lazy Loading in der gesamten Anwendung. Seitdem Angular 19 Standalone zum Standard erklärt hat und Angular 21 die zoneless Change Detection gefestigt hat, ist die Migration alter modulbasierter Codebasen sowohl unkompliziert als auch wirkungsvoll geworden.
Das offizielle Angular-CLI-Schematic übernimmt den Großteil der Migration automatisch in drei Durchgängen. Eine typische Enterprise-Anwendung kann die Konvertierung in einem einzigen Sprint abschließen, wobei die Bundle-Größen dank komponentenbezogenem Lazy Loading um 30-50 % schrumpfen.
NgModules vs. Standalone Components: Was sich geändert hat
NgModules dienten seit Angular 2 als Kompilierungskontext für Komponenten. Jede Komponente, Direktive und Pipe musste in genau einem Modul deklariert werden, und gemeinsam genutzte Funktionalität erforderte sorgfältig orchestrierte Modul-Imports und -Exports. Dies führte zu enger Kopplung zwischen unabhängigen Features und erschwerte das Tree-Shaking.
Standalone Components kehren dieses Modell um. Jede Komponente deklariert ihre eigenen Abhängigkeiten direkt im imports-Array des @Component-Decorators. Keine Modulregistrierung, keine geteilten Module, keine Barrel-Exports der halben Anwendung.
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('');
}Das imports-Array ersetzt den gesamten NgModule-Abhängigkeitsgraphen. Der Bundler sieht genau, welche Komponenten, Pipes und Direktiven jede Datei benötigt, was präzises Tree-Shaking ermöglicht.
Der 3-stufige CLI-Migrationsprozess
Angular bietet ein automatisiertes Schematic, das die Migration in drei aufeinanderfolgenden Durchgängen abwickelt. Jeder Schritt baut auf dem vorherigen auf, und das Projekt sollte zwischen den Durchgängen sauber kompilieren.
Schritt 1: Deklarationen in Standalone umwandeln
Der erste Durchgang scannt jede Komponente, Direktive und Pipe im Projekt, fügt standalone: true hinzu und verschiebt die notwendigen Imports aus dem übergeordneten NgModule in das eigene imports-Array jeder Komponente.
# Step 1: Convert all declarations to standalone
ng g @angular/core:standalone --path=src/appWählen Sie bei der Aufforderung "Convert all components, directives and pipes to standalone" aus. Das Schematic verwendet statische Analyse zur Auflösung von Abhängigkeiten, daher werden Komponenten mit Metadaten, die zur Build-Zeit nicht analysiert werden können, mit einer Warnung übersprungen.
Schritt 2: Überflüssige NgModules entfernen
Da nun alle Deklarationen Standalone sind, werden viele NgModules zu leeren Hüllen. Dieser Durchgang identifiziert Module, die nur Standalone-Deklarationen re-exportiert haben, und entfernt sie.
# Step 2: Remove empty NgModules
ng g @angular/core:standalone --path=src/appWählen Sie "Remove unnecessary NgModule classes". Module, die noch Provider, Routenkonfigurationen enthalten oder von mehreren anderen Modulen importiert werden, bleiben mit einem TODO-Kommentar zur manuellen Überprüfung erhalten.
Schritt 3: Auf Standalone-Bootstrap umstellen
Der letzte Durchgang ersetzt das Root-NgModule durch Angulars bootstrapApplication-API und konvertiert die Root-Komponente in 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]))
]
};Das ApplicationConfig-Muster ersetzt die providers- und imports-Arrays des Root-Moduls. Alle Provider-Funktionen (provideRouter, provideHttpClient, provideAnimations) funktionieren direkt ohne Modul-Wrapper.
Routing-Migration: Von Modulen zu loadComponent
Routing-Module erfordern manuelle Aufmerksamkeit, da das Schematic loadChildren-Modul-Imports nicht automatisch in loadComponent oder Routen-Level-loadChildren mit Standalone-Routen konvertiert.
Das alte Muster lud ganze Feature-Module:
const routes: Routes = [
{
path: 'dashboard',
loadChildren: () => import('./dashboard/dashboard.module')
.then(m => m.DashboardModule)
}
];Das Standalone-Äquivalent lädt einzelne Komponenten oder Routendateien direkt:
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 lädt eine einzelne Komponente per Lazy Loading. loadChildren mit einer Routendatei lädt einen ganzen Feature-Bereich per Lazy Loading. Beide erzeugen separate Chunks, die der Browser bei Bedarf abruft.
Bereit für deine Angular-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
Umgang mit SharedModules und gemeinsamen Abhängigkeiten
SharedModules — die Sammelmodule, die häufig verwendete Komponenten, Direktiven und Pipes exportieren — sind das häufigste Hindernis bei der Migration. Das Schematic kann sie nicht automatisch entfernen, da mehrere Module sie importieren.
Die Lösung: gemeinsame Deklarationen einzeln in Standalone konvertieren und das SharedModule löschen, sobald nichts mehr es importiert.
// 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 {}Konsumenten importieren LoadingSpinner jetzt direkt anstelle des gesamten SharedModule. Der Bundler bezieht nur die spezifischen Komponenten ein, die jede Route benötigt.
Standalone-Only-Entwicklung erzwingen
Nach der Migration ist es entscheidend zu verhindern, dass neue NgModules wieder in die Codebasis einsickern. Angular bietet dafür eine TypeScript-Compiler-Option.
{
"angularCompilerOptions": {
"strictStandalone": true
}
}Mit aktiviertem strictStandalone führt jeder Versuch, eine nicht-standalone Komponente, Direktive oder Pipe zu erstellen, zu einem Kompilierungsfehler. Dies erzwingt die neue Architektur im gesamten Team.
Performance-Gewinne: Bundle-Größe und Lazy Loading
Der primäre Performance-Vorteil von Standalone Components ergibt sich aus granularem Lazy Loading. Mit NgModules funktionierte Lazy Loading auf Modulebene — der Import einer Komponente aus einem Modul zog jede Deklaration mit, die das Modul exportierte. Standalone Components durchbrechen diese Kopplung.
Ein Real-World-Benchmark mit einer mittelgroßen Enterprise-Anwendung (200+ Komponenten) zeigte:
| Metrik | NgModule-basiert | Standalone | Verbesserung | |--------|---------------|------------|-------------| | Initial Bundle | 485 KB | 218 KB | -55 % | | Größter Lazy-Chunk | 142 KB | 38 KB | -73 % | | Time to Interactive | 3,2 s | 1,8 s | -44 % | | Build-Zeit (esbuild) | 12,4 s | 8,1 s | -35 % |
Diese Zahlen ergeben sich aus dem Wegfall des Overheads der Modulauflösung und der Möglichkeit für den Bundler, ungenutzte Exporte auf Komponentenebene statt auf Modulebene zu eliminieren.
Standalone Components testen
Unit-Tests werden mit Standalone Components deutlich einfacher. Die TestBed-Konfiguration erfordert nicht länger den Import ganzer Module, um die Abhängigkeiten einer Komponente zu erfüllen.
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);
});
});Die Komponente landet direkt im imports-Array von TestBed.configureTestingModule. Alle deklarierten Abhängigkeiten sind bereits über das eigene imports aufgelöst, sodass keine zusätzlichen Modul-Imports nötig sind.
Häufige Migrationsfallen
Zirkuläre Imports zwischen Standalone Components. Wenn Komponente A Komponente B importiert und B wiederum A, wirft der TypeScript-Compiler einen Fehler wegen zirkulärer Abhängigkeit. Die Lösung: das gemeinsame Interface in eine separate Datei extrahieren oder forwardRef() als temporären Workaround verwenden, während die Abhängigkeitskette refaktoriert wird.
Drittanbieter-Bibliotheken nutzen noch NgModules. Viele Bibliotheken sind zu Standalone migriert, einige Legacy-Pakete exportieren jedoch weiterhin NgModules. Diese Module können direkt im imports-Array der Standalone-Komponente importiert werden — Angular unterstützt das Mischen von Standalone- und modulbasierten Imports.
Fehlende Provider nach Entfernung des AppModule. Services, die zuvor im providers-Array des Root-Moduls bereitgestellt wurden, müssen in das ApplicationConfig in app.config.ts verschoben werden oder providedIn: 'root' im @Injectable-Decorator verwenden. Routen-bezogene Services sollten das providers-Array in den Routenkonfigurationen nutzen.
Fang an zu üben!
Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.
Fazit
- Das offizielle Angular-CLI-Schematic automatisiert 80-90 % der Migration durch drei aufeinanderfolgende Durchgänge: Deklarationen konvertieren, Module entfernen, Bootstrap umstellen
- Routing-Module benötigen eine manuelle Konvertierung von
loadChildrenmit NgModules zuloadComponentoder Standalone-Routendateien - SharedModules sind das Hauptproblem — jede gemeinsame Deklaration einzeln in Standalone konvertieren und dann das Modul löschen
strictStandalonein der tsconfig aktivieren, um zu verhindern, dass nach der Migration neue NgModules eingeführt werden- Bundle-Größen sinken um 30-55 % dank komponentenbezogenem Tree-Shaking und granularem Lazy Loading mit
loadComponent - Unit-Tests werden drastisch einfacher — die Standalone-Komponente direkt in
TestBedohne Modulkonfiguration importieren - Angular 21s zoneless Change Detection und signal-basierte Reaktivität passen perfekt zur Standalone-Architektur für maximale Performance
Fang an zu üben!
Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.
Tags
Teilen
Verwandte Artikel

Angular 19 Zoneless: Performance und Change Detection ohne Zone.js
Umfassender technischer Leitfaden zur Zoneless Change Detection in Angular 19 und 20. Funktionsweise der Signal-basierten Reaktivitaet, Aktivierung von provideZonelessChangeDetection, Migration von Zone.js-abhaengigem Code, Reactive Forms im Zoneless-Modus, SSR mit PendingTasks und Performance-Benchmarks im direkten Vergleich.

Top 25 Angular-Interviewfragen: Vollständiger Leitfaden zum Erfolg
Die 25 häufigsten Angular-Interviewfragen 2026. Detaillierte Antworten, Codebeispiele und Tipps, um die Stelle als Angular-Entwickler zu sichern.

Angular 18: Signals und neue Features
Angular 18 Signals, zoneless Change Detection und die neuen signal-basierten APIs fuer performantere Anwendungen im Ueberblick.