| name | angular-best-practices |
| description | Angular performance optimization and best practices guide. Use when writing, reviewing, or refactoring Angular code for optimal performance, bundle size, and rendering efficiency. |
| category | AI & Agents |
| source | antigravity |
| tags | ["typescript","api","ai","template","cro"] |
| url | https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/angular-best-practices |
Angular Best Practices
Comprehensive performance optimization guide for Angular applications. Contains prioritized rules for eliminating performance bottlenecks, optimizing bundles, and improving rendering.
When to Use
Reference these guidelines when:
- Writing new Angular components or pages
- Implementing data fetching patterns
- Reviewing code for performance issues
- Refactoring existing Angular code
- Optimizing bundle size or load times
- Configuring SSR/hydration
Rule Categories by Priority
| Priority | Category | Impact | Focus |
|---|
| 1 | Change Detection | CRITICAL | Signals, OnPush, Zoneless |
| 2 | Async Waterfalls | CRITICAL | RxJS patterns, SSR preloading |
| 3 | Bundle Optimization | CRITICAL | Lazy loading, tree shaking |
| 4 | Rendering Performance | HIGH | @defer, trackBy, virtualization |
| 5 | Server-Side Rendering | HIGH | Hydration, prerendering |
| 6 | Template Optimization | MEDIUM | Control flow, pipes |
| 7 | State Management | MEDIUM | Signal patterns, selectors |
| 8 | Memory Management | LOW-MEDIUM | Cleanup, subscriptions |
1. Change Detection (CRITICAL)
Use OnPush Change Detection
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
template: `<div>{{ count() }}</div>`,
})
export class CounterComponent {
count = signal(0);
}
@Component({
template: `<div>{{ count }}</div>`,
})
export class CounterComponent {
count = 0;
}
Prefer Signals Over Mutable Properties
@Component({
template: `
<h1>{{ title() }}</h1>
<p>Count: {{ count() }}</p>
`,
})
export class DashboardComponent {
title = signal("Dashboard");
count = signal(0);
}
@Component({
template: `
<h1>{{ title }}</h1>
<p>Count: {{ count }}</p>
`,
})
export class DashboardComponent {
title = "Dashboard";
count = 0;
}
Enable Zoneless for New Projects
bootstrapApplication(AppComponent, {
providers: [provideZonelessChangeDetection()],
});
Benefits:
- No zone.js patches on async APIs
- Smaller bundle (~15KB savings)
- Clean stack traces for debugging
- Better micro-frontend compatibility
2. Async Operations & Waterfalls (CRITICAL)
Eliminate Sequential Data Fetching
this.route.params.subscribe((params) => {
this.userService.getUser(params.id).subscribe((user) => {
this.postsService.getPosts(user.id).subscribe((posts) => {
});
});
});
forkJoin({
user: this.userService.getUser(id),
posts: this.postsService.getPosts(id),
}).subscribe((data) => {
});
this.route.params
.pipe(
map((p) => p.id),
switchMap((id) => ..(id)),
)
.();
Avoid Client-Side Waterfalls in SSR
export const route: Route = {
path: "profile/:id",
resolve: { data: profileResolver },
component: ProfileComponent,
};
class ProfileComponent implements OnInit {
ngOnInit() {
this.http.get("/api/profile").subscribe();
}
}
3. Bundle Optimization (CRITICAL)
Lazy Load Routes
export const routes: Routes = [
{
path: "admin",
loadChildren: () =>
import("./admin/admin.routes").then((m) => m.ADMIN_ROUTES),
},
{
path: "dashboard",
loadComponent: () =>
import("./dashboard/dashboard.component").then(
(m) => m.DashboardComponent,
),
},
];
import { AdminModule } from "./admin/admin.module";
export const routes: Routes = [
{ path: "admin", component: AdminComponent },
];
Use @defer for Heavy Components
@defer (on viewport) {
<app-analytics-chart [data]="data()" />
} @placeholder {
<div class="chart-skeleton"></div>
}
<app-analytics-chart [data]="data()" />
Avoid Barrel File Re-exports
import { Button, Moda