Angular Best Practices
Angular's structure and conventions are more opinionated than some frameworks, and working with that structure — rather than around it — is what keeps a growing Angular application maintainable.
Last updated 2026-09-08
Use OnPush change detection where possible
Default change detection checks every component on every change-detection cycle, which gets expensive as an app grows. OnPush, combined with immutable data patterns, only re-checks a component when its inputs actually change by reference.
Unsubscribe from Observables to avoid memory leaks
A subscription inside a component that's never cleaned up keeps running even after the component is destroyed. Use the async pipe where possible (which handles unsubscription automatically), or explicitly unsubscribe in ngOnDestroy.
Keep components focused — move business logic into services
A component with heavy business logic mixed into it is hard to test and hard to reuse. Services (injected via Angular's DI system) should hold logic and data-fetching; components should focus on presentation and user interaction.
Use trackBy with *ngFor for lists
Without trackBy, Angular re-renders the entire list on any change by default, comparing by object identity. A trackBy function lets Angular efficiently update only the items that actually changed.
Lazy-load feature modules
Loading the entire application's code upfront slows initial load time. Lazy-loading feature modules means users only download the code for the part of the app they're actually using.
Common Mistakes to Avoid
- ⚠Subscribing to an Observable in a component without ever unsubscribing
- ⚠Heavy business logic inside components instead of services
- ⚠*ngFor without trackBy on large or frequently-updated lists
- ⚠Not using OnPush change detection where the component's data pattern would support it
- ⚠Loading all feature modules eagerly instead of lazy-loading
Frequently Asked Questions
Should I use RxJS or signals for state in modern Angular?
Signals (introduced more recently) are increasingly recommended for straightforward reactive state due to their simpler mental model, while RxJS remains the right tool for genuinely complex async event streams and operators — many real apps use both where each fits best.
Is the async pipe always better than manual subscription?
For template-bound Observables, yes generally — it handles subscription and unsubscription automatically, removing a common source of memory leaks that manual subscription management is prone to.