# Frontend performance rules for enterprise apps

Source: https://tt-tech.io/blog/frontend-performance-enterprise-budgets
For Angular and React frontends. Add to AGENTS.md or save as a skill. Your project's own rules win where they differ.

## Rules

1. Keep a `budgets` section in the build configuration (`angular.json` or `project.json`) with `maximumWarning` and `maximumError`. Start with `initial` and `anyComponentStyle`. Add per-bundle budgets when a lazy feature starts to grow.
2. When there is no budget, or the error limit is far above today's size, set it just above the current initial bundle.
3. Load each feature through its own lazy route. Code that belongs to another screen goes in a lazy route; a heavy widget below the fold on the same screen (a chart, an editor) goes in `@defer`. In React, use `lazy` with a `<Suspense>` fallback.
4. Track every `@for` by a stable id (`track item.id`), never by object reference. Give React lists rendered with `.map()` a stable key in the same way.
5. For long lists, paginate on the server when users search and filter. Use virtual scroll (`<cdk-virtual-scroll-viewport>`) when they really scan a long list on one page. Virtual scroll fixes rendering, not downloading.
6. In image-heavy Angular screens, use `NgOptimizedImage` (`<img ngSrc>`, not `<img src>`) with a width and height, and `sizes` for the `srcset`. Mark the main image of the page `priority`.
7. Judge Core Web Vitals at the 75th percentile of page loads, mobile and desktop apart, never by average. Good is LCP within 2.5 seconds, INP at 200 milliseconds or less, CLS at 0.1 or less.
8. On data-heavy screens (filters, sorting, opening a row), watch INP first.
9. Use lab data (Lighthouse in CI) to catch regressions and field data from real users to decide what to fix. A run on a developer machine is not what users get.
10. Add `preload`, `prefetch` or `preconnect` only when a measurement shows a resource arrives late, not by default.

## Before you say done

- Run the production build. It must pass the budgets. Report any new budget warning and the initial bundle size before and after.
- Search the diff for `@for` blocks that track by object or `$index`, and for `.map()` lists without a stable key.
- Search the diff for `<img src` in Angular templates, and for heavy libraries imported outside a lazy route or `@defer`.
