Eine Angular-Anwendung wird schnell unübersichtlich, wenn jede neue Funktion erst über mehrere NgModule verdrahtet werden muss. Standalone Components lösen genau dieses Problem, indem sie ihre Abhängigkeiten direkt am Baustein deklarieren. Ich zeige, wie das Modell funktioniert, welche Vorteile es im Alltag bringt, wann NgModules weiterhin eine Rolle spielen und wie sich bestehende Projekte sicher umstellen lassen.
Standalone Components machen Angular modularer und direkter
-
Direkte Abhängigkeiten werden im Feld
importsder Component festgelegt. - NgModules sind für neue Angular-Projekte meist nicht mehr der notwendige Einstiegspunkt.
- bootstrapApplication startet eine Anwendung direkt über ihre Root-Component.
-
Lazy Loading wird mit
loadComponentbesonders übersichtlich. - Migrationen sollten schrittweise erfolgen und nach jedem Schritt getestet werden.

Was eine standalone Component in Angular anders macht
Die englische Bezeichnung angular standalone component steht für eine Angular-Component, die ohne Eintrag in einem NgModule verwendet werden kann. Sie bringt ihre benötigten Components, Direktiven und Pipes direkt über imports mit. Dadurch ist auf einen Blick erkennbar, wovon der Baustein tatsächlich abhängt.
In älteren Angular-Projekten lagen diese Informationen häufig in einem Modul. Eine Component wurde dort unter declarations registriert, ein gemeinsames Modul exportierte sie und ein anderes importierte dieses Modul wieder. Das funktionierte, erzeugte aber schnell indirekte Abhängigkeiten, die bei größeren Teams schwer nachzuvollziehen waren.
Eine Standalone Component ist deshalb nicht einfach eine Component mit einem anderen Schalter. Sie verändert die Struktur der Anwendung. Ich empfinde besonders die klare lokale Zuständigkeit als Gewinn: Wer eine Datei öffnet, sieht meist sofort, welche UI-Bausteine und Template-Funktionen sie verwendet.
Was weiterhin gleich bleibt
Die Component besteht nach wie vor aus einer TypeScript-Klasse, einem Template und optionalen Styles. Inputs, Outputs, Dependency Injection, Routing und Lifecycle Hooks funktionieren weiterhin nach denselben Grundprinzipien. Standalone bedeutet nicht eigenständig im fachlichen Sinn, sondern unabhängig von einem NgModule.
Auch bestehende NgModules verschwinden nicht automatisch. Eine Standalone Component kann weiterhin ein vorhandenes NgModule importieren, wenn eine Bibliothek noch keine eigenständigen Direktiven oder Provider anbietet. Das macht die Umstellung deutlich weniger riskant, als viele zunächst vermuten.
So baust du eine Standalone Component auf
Eine einfache Component lässt sich mit der Angular CLI erzeugen. Bei aktuellen CLI-Projekten ist die Standalone-Variante der übliche Standard, ich schreibe die Einstellung im Beispiel trotzdem ausdrücklich hin. So wird die Architektur auch für Personen verständlich, die aus einem älteren Projekt kommen.
ng generate component product-card
Das folgende Beispiel zeigt eine kleine Produktkarte mit einer Pipe und einer Benutzeraktion.
import { CurrencyPipe } from '@angular/common';
import { Component } from '@angular/core';
@Component({
selector: 'app-product-card',
standalone: true,
imports: [CurrencyPipe],
template: `
{{ name }}
{{ price | currency:'EUR' }}
`
})
export class ProductCardComponent {
name = 'Noise-Cancelling-Kopfhörer';
price = 129.99;
addToCart(): void {
console.log('Produkt hinzugefügt');
}
}Der entscheidende Punkt ist imports: [CurrencyPipe]. Die Pipe wird nicht in einem gemeinsamen Modul bereitgestellt, sondern dort importiert, wo sie im Template gebraucht wird. Fehlt der Import, meldet Angular normalerweise schon beim Kompilieren, dass die verwendete Template-Funktion nicht bekannt ist.
Andere Components direkt einbinden
Eine Standalone Component wird in einer anderen Standalone Component ebenfalls direkt importiert. Zusätzlich muss sie im imports-Array der aufrufenden Component stehen.
import { Component } from '@angular/core';
import { ProductCardComponent } from './product-card.component';
@Component({
selector: 'app-shop',
standalone: true,
imports: [ProductCardComponent],
template: `
Unser Shop
`
})
export class ShopComponent {}
Dieser Aufbau wirkt anfangs etwas ausführlicher, ist aber langfristig sauberer. Die Abhängigkeit ist lokal sichtbar und nicht über eine Kette aus SharedModule, FeatureModule und RootModule verteilt.
Direktiven und Pipes gezielt importieren
Für einzelne Template-Funktionen importiere ich möglichst nur das, was wirklich verwendet wird. Bei klassischer Syntax wären das etwa NgIf, NgFor oder AsyncPipe. Moderne Angular-Projekte können außerdem die eingebaute Control-Flow-Syntax mit @if und @for nutzen, wodurch einige Importe über CommonModule entfallen.
Das ist kein Grund, jedes Template zwanghaft umzuschreiben. Entscheidend ist, dass die Component verständlich bleibt und der Build keine unnötigen Abhängigkeiten mitschleppt. Kleine, präzise Imports sind in meinen Augen hilfreicher als eine scheinbar elegante, aber schwer erkennbare Sammellösung.
Bootstrap, Routing und Services ohne NgModule organisieren
Standalone betrifft nicht nur einzelne UI-Bausteine. Eine Anwendung kann auch direkt über ihre Root-Component gestartet werden. Dafür wird bootstrapApplication verwendet.
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
bootstrapApplication(AppComponent)
.catch(error => console.error(error));
Die Root-Component muss standalone sein. Globale Provider wie HTTP, Router, Authentifizierung oder Konfiguration gehören in die Bootstrap-Konfiguration und nicht in eine künstliche Modulstruktur.
import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient } from '@angular/common/http';
import { provideRouter } from '@angular/router';
import { AppComponent } from './app/app.component';
import { routes } from './app/app.routes';
bootstrapApplication(AppComponent, {
providers: [
provideHttpClient(),
provideRouter(routes)
]
}).catch(error => console.error(error));
Hier zeigt sich ein wichtiger Unterschied: Components importieren UI-Abhängigkeiten, während die Anwendung globale Services über Provider konfiguriert. Diese Trennung verhindert, dass beispielsweise ein API-Service versehentlich nur innerhalb eines einzelnen Templates verfügbar ist.
Lazy Loading wird besonders übersichtlich
Für größere Anwendungen ist die Kombination aus Standalone Components und Lazy Loading sehr praktisch. Eine Route kann eine Component erst laden, wenn der entsprechende Bereich tatsächlich aufgerufen wird.
import { Routes } from '@angular/router';
export const routes: Routes = [
{
path: 'einstellungen',
loadComponent: () =>
import('./settings/settings.component')
.then(module => module.SettingsComponent)
}
];
Das reduziert nicht automatisch jede Ladezeit auf einen bestimmten Wert. Der tatsächliche Effekt hängt von Bundle-Größe, Bildern, Drittanbieterpaketen und Server-Konfiguration ab. In der Praxis entsteht aber eine klarere Aufteilung der JavaScript-Bundles, vor allem bei Anwendungen mit vielen selten besuchten Bereichen.
NgModule-Bibliotheken schrittweise weiterverwenden
Eine ältere Bibliothek muss nicht sofort ersetzt werden. Für ihre Provider kann importProvidersFrom verwendet werden. Das ist besonders nützlich, wenn ein Paket noch eine Konfiguration über ein NgModule erwartet.
bootstrapApplication(AppComponent, {
providers: [
importProvidersFrom(LegacyModule)
]
});
Ich würde diese Möglichkeit als Brücke für eine Übergangsphase betrachten, nicht als Zielarchitektur. Sie hilft, Abhängigkeiten zu modernisieren, ohne eine komplette Anwendung an einem einzigen Wochenende umzubauen.
Standalone oder NgModule welches Modell passt besser
Für neue Angular-Anwendungen empfiehlt die Angular-Dokumentation den Standalone-Ansatz. Trotzdem ist ein NgModule-basiertes Projekt nicht automatisch veraltet oder schlecht strukturiert. Die bessere Entscheidung hängt von Codebasis, Team, Bibliotheken und geplanter Lebensdauer ab.
| Kriterium | Standalone Components | NgModules |
|---|---|---|
| Neue Projekte | Meist die klarere Wahl | Nur bei konkretem Kompatibilitätsgrund |
| Abhängigkeiten | Direkt an der Component sichtbar | Oft über Module gebündelt |
| Lazy Loading | Mit loadComponent sehr direkt |
Häufig über Lazy-loaded NgModules |
| Migration | Für neue Bereiche sofort nutzbar | Kann zunächst weiterlaufen |
| Bibliothekskompatibilität | Gut, aber abhängig von der jeweiligen Bibliothek | Bei älteren Paketen oft unkomplizierter |
Für ein neues Produkt würde ich heute mit Standalone starten. Bei einem großen Bestandssystem mit stabilen NgModules sehe ich dagegen keinen Wert darin, jede Datei nur aus Prinzip umzubauen. Technische Migrationen sollten ein Problem lösen, etwa schwer verständliche Abhängigkeiten, langsame Builds oder eine neue Routing-Struktur.
Ein häufiger Denkfehler ist außerdem die Erwartung, Standalone Components würden automatisch eine deutlich kleinere Anwendung erzeugen. Sie können Abhängigkeiten präziser machen und Lazy Loading erleichtern, aber die Architektur ersetzt keine Bundle-Analyse. Unnötige UI-Bibliotheken, große Datenpakete und falsch konfigurierte Polyfills bleiben auch in einer Standalone-Anwendung problematisch.
Ein bestehendes Projekt sicher migrieren
Angular stellt für die Umstellung ein offizielles Migrations-Schematic bereit. Der sichere Weg besteht aus mehreren Durchläufen. Vor dem Start sollte das Projekt ohne Compilerfehler bauen und der aktuelle Stand in einem sauberen Git-Branch gesichert sein.
-
Components, Direktiven und Pipes konvertieren und ihre Template-Abhängigkeiten in
importsverschieben. - Überflüssige NgModules entfernen, nachdem die erste Version erfolgreich kompiliert.
-
Das Bootstrap-Verfahren umstellen und
bootstrapModuledurchbootstrapApplicationersetzen. - Tests, Linting und Formatierung ausführen und verbleibende manuelle Stellen prüfen.
ng generate @angular/core:standalone
Das Werkzeug automatisiert viel, aber nicht alles. Es kann Schwierigkeiten mit dynamisch erzeugten Metadaten, eigenen Wrappern um Angular-APIs oder Dateien geben, die nicht in der verwendeten TypeScript-Konfiguration enthalten sind. Deshalb würde ich nach jedem Migrationsschritt bauen und testen, statt alle Änderungen am Ende gesammelt zu kontrollieren.
Lesen Sie auch: Publisher im Web - Aufgaben, Rollen und Publishing-Workflow
Tests müssen ebenfalls angepasst werden
Bei einer Standalone Component gehört die getestete Component in vielen TestBed-Konfigurationen zu imports und nicht zu declarations.
await TestBed.configureTestingModule({
imports: [ProductCardComponent]
}).compileComponents();
Gerade bei großen Test-Suites tauchen solche Fehler oft erst spät auf. Ich plane deshalb die Anpassung der Tests nicht als Nacharbeit ein, sondern als festen Teil jedes Migrationsschritts. Das spart Zeit und zeigt schneller, ob die neue Importstruktur tatsächlich vollständig ist.
Typische Fehler bei der täglichen Arbeit
Der häufigste Fehler ist ein fehlender Import. Eine Component verwendet beispielsweise eine Pipe oder ein Kind-Element im Template, führt es aber nicht in imports auf. Der Compiler hilft hier zwar, doch bei komplexen Templates kann die Fehlermeldung zunächst verwirrend wirken.
Ein zweites Problem entsteht durch zu große Sammel-Components. Standalone macht es leicht, viele Abhängigkeiten direkt einzutragen. Das bedeutet aber nicht, dass eine einzelne Page-Component plötzlich für Formulare, Navigation, Datenzugriff und Modalfenster zuständig sein sollte. Lokale Imports verbessern die Struktur nur dann, wenn die fachlichen Grenzen ebenfalls sinnvoll gesetzt sind.
Auch Provider werden gelegentlich am falschen Ort registriert. Ein globaler Authentifizierungsdienst gehört meist in die Anwendungskonfiguration, ein zustandsbezogener Dienst für einen bestimmten Bereich kann dagegen an einer Route oder Component sinnvoll sein. Der richtige Ort hängt davon ab, wie lange die Instanz leben und wer sie teilen soll.
Schließlich sollte niemand NgModules aus einer funktionierenden Legacy-Bibliothek gewaltsam entfernen. Eine schrittweise Mischung ist erlaubt und oft vernünftig. Erst wenn Ersatzpakete, Tests und Build-Prozess stabil sind, lohnt sich die vollständige Bereinigung.
Die wichtigste Architekturentscheidung liegt nicht im Decorator
Eine Standalone Component ist vor allem ein Werkzeug für klare Abhängigkeiten, kleinere Zuständigkeiten und flexibleres Routing. Der eigentliche Nutzen entsteht nicht durch das einzelne standalone: true, sondern durch die konsequente Entscheidung, Verantwortlichkeiten sichtbar und lokal zu halten.
Für neue Angular-Projekte ist der Einstieg unkompliziert: Component erzeugen, benötigte UI-Bausteine importieren, globale Provider beim Bootstrap konfigurieren und große Bereiche über Routen lazy laden. Bestehende Anwendungen dürfen langsamer wachsen. In meinen Projekten ist eine kontrollierte Teilmigration meist wertvoller als ein riskanter Komplettumbau.
Wer diese Grenzen beachtet, bekommt keine magische Performance-Lösung, aber eine Angular-Codebasis, die sich leichter lesen, testen und weiterentwickeln lässt. Genau darin liegt für mich der nachhaltige Vorteil des Standalone-Modells.