Frontend Performance
Acknowledgement: Shared by Peter Bamuhigire, techguypeter.com, +256 784 464178.
Specialist frontend skill. Produces the three deliverables that give a team an operable performance posture: a budget per critical flow, a measurement plan tied to the SLO set, and a regression gate in CI. Not a generic optimisation checklist.
Prerequisites: Load system-architecture-design (for the critical-flow table) and observability-monitoring (for the SLO set and RUM dashboard conventions) before this skill. Load react-development or nextjs-app-router if the stack is React/Next.
Use When
- Defining the performance budget for a new product or critical flow.
- Diagnosing a field regression on LCP, INP, or CLS captured by RUM.
- Wiring up a regression gate before a team scales frontend merges.
- Auditing an existing frontend and translating findings into budgets and gates.
- Choosing between inline CSS vs deferred, server vs client rendering, or route vs component code-split.
Do Not Use When
- The bottleneck is server latency or database query time — use
observability-monitoring, the relevant database skill, or reliability-engineering.
- The work is API contract design — use
api-design-first.
- The work is pure visual/interaction design without a measurable performance cost — use the UI/UX baseline skills.
Required Inputs
- Critical-flow table from
system-architecture-design.
- SLO set and RUM dashboard conventions from
observability-monitoring.
- Device and network mix for the target user base.
Workflow
- Read this SKILL.md, then load
references/budgets-and-regression-gate.md plus whichever of loading-performance.md, rendering-and-inp.md, framework-recipes.md the task requires.
- Produce the three deliverables (budget, measurement plan, regression gate) before chasing individual optimisations.
- Tie every SLI back to an SLO owned by
observability-monitoring.
Quality Standards
- Budget rows and SLIs map one-to-one with critical flows and SLOs; no orphan metrics.
- Gate is blocking in CI, not advisory.
- Field measurement (RUM) is primary; lab measurement is a leading indicator.
Anti-Patterns
- Chasing Lighthouse score without a field measurement plan.
- Declaring a budget without naming the device class and network.
- Adding a regression gate that only warns and never blocks.
Outputs
- Performance budget per critical flow.
- Measurement plan (SLIs, source, reporting surface, alert thresholds).
- Regression gate in CI.
Evidence Produced
| Category |
Artifact |
Format |
Example |
| Performance |
Performance budget document |
Markdown doc stating page, API, and interaction budgets |
docs/performance/budgets-checkout.md |
| Performance |
Real-user and synthetic metrics evidence |
Dashboard link plus archived snapshot |
docs/performance/rum-snapshot-2026-04-16.md |
Capability contract
Read and search the application and measurement configuration first. Editing and execution require authorisation; when available, run the existing build, bundle analysis, lab checks, and relevant tests. Network access is optional for current browser guidance.
references/budgets-and-regression-gate.md
references/loading-performance.md
references/rendering-and-inp.md
references/framework-recipes.md
When this skill applies
- Establishing a performance budget for a new product or each critical flow in an existing product.
- Investigating a field regression in LCP, INP, or CLS flagged by RUM.
- Designing a CI regression gate before the team scales frontend merges.
- Auditing an existing frontend and producing budgets plus gates, not just a "make it faster" ticket list.
- Choosing between competing rendering strategies (SSR vs SSG vs CSR, inline vs deferred CSS, route vs component split).
Inputs
| Artifact |
Produced by |
Required? |
Why |
| Critical-flow table |
system-architecture-design |
required |
Budgets are defined per critical flow, not per page |
| SLO set |
observability-monitoring |
required |
Frontend SLIs must align with owned SLOs and alert pipelines |
| RUM dashboard conventions |
observability-monitoring |
required |
Where field measurements are reported and alerted |
| Device + network mix |
product/analytics |
required |
Determines the reference device class and throttling profile |
| API error model |
api-design-first |
optional |
Informs retry + fallback UI budget |
| Threat model |
vibe-security-skill |
optional |
Gates CSP and third-party script decisions |
Outputs
| Artifact |
Consumed by |
Template |
| Performance budget per critical flow |
deployment-release-engineering, observability-monitoring, QA |
references/budgets-and-regression-gate.md |
| Measurement plan (SLIs, sources, reporting, thresholds) |
observability-monitoring, on-call |
references/budgets-and-regression-gate.md |
| Regression gate in CI |
cicd-pipelines, deployment-release-engineering |
references/budgets-and-regression-gate.md |
| Framework recipe notes |
react-development, nextjs-app-router, Vue/Nuxt specialists |
references/framework-recipes.md |
Non-negotiables
- A budget is stated per critical flow with an explicit device class and network.
- Every SLI maps to an SLO owned by
observability-monitoring; no stand-alone frontend dashboards.
- Regression gate blocks merges when thresholds are breached; it is not advisory.
- Field measurements (
web-vitals beaconed to RUM) drive alerting. Lab metrics (Lighthouse CI) are a PR leading indicator only.
- Core Web Vitals targets: LCP p75 < 2.5s, INP p75 < 200ms, CLS p75 < 0.1 — unless a flow-specific budget supersedes them with written justification.
Decision rules
Rendering strategy
Mostly static marketing / docs / blog -> SSG (or ISR with long revalidate)
Authenticated dashboard, per-user data -> SSR streaming + client islands
Highly interactive tool (editor, canvas) -> CSR with aggressive code-split
Tenant-scoped SaaS app, mixed criticality -> Server components + selective client
Wrong choice failure mode:
- SSG for per-user data -> stale personalisation, auth leaks across caches
- SSR for heavy interactivity -> slow TTFB, wasted server render on cold data
- CSR for content-first pages -> poor LCP, poor SEO
Inline CSS vs deferred
Above-fold critical path, < 14KB critical CSS -> inline in <head>
Route-specific, bulky, cachable -> external file, async preload
Third-party widget CSS (chat, analytics UI) -> defer, load after interaction
Design tokens / reset / typography base -> inline (tiny, load-blocking is fine)
Wrong choice failure mode:
- Inline everything -> bloated HTML, no CSS caching across navigations
- Defer critical styles -> FOUC and layout shift on first paint
Code splitting strategy
Route-based split -> default for every SPA/Next route
Component-level dynamic import -> heavy widget (editor, chart, map) > 30KB
Vendor split (react/react-dom) -> long-cache chunk, rarely updated
No split -> only for single-page tools under 150KB total
Wrong choice failure mode:
- Over-splitting tiny chunks -> HTTP request overhead + waterfall
- Single monolithic bundle -> blocks initial interactivity, poor INP
Image handling
Hero / LCP candidate -> eager, fetchpriority=high, preload
Above fold, non-LCP -> eager, default priority
Below fold -> loading=lazy, decoding=async
Vector/icon under 2KB -> inline SVG (no request)
Repeat background -> CSS background with responsive image-set()
Wrong choice failure mode:
- Lazy-loading LCP -> catastrophic LCP regression
- Eager-loading below fold -> bandwidth waste, contention with LCP
When to add a new SLI
Metric exists and alert correlates with user-visible harm -> keep, publish on dashboard
Metric is a proxy with no known user impact -> do not alert, log for investigation
Metric is a per-flow variant of a global SLI -> add as dimension, not new SLI
Metric overlaps a backend SLO -> owned by observability-monitoring, not here
Core content
The three deliverables below are the contract. Everything else in references/ supports producing them.
1. Performance budget per critical flow
For each row in the upstream critical-flow table, declare: target device class, target network, LCP, INP, CLS, compressed JS, compressed CSS, total compressed transfer, image-LCP cap. Example table and rules: references/budgets-and-regression-gate.md.
2. Measurement plan
For every SLI: the source (field or lab), the beacon/collector, the dashboard where it is reported, and the alert threshold. Field measurements use web-vitals JS beaconed to the RUM backend defined by observability-monitoring. Lab measurements use Lighthouse CI in the merge pipeline.
3. Regression gate
A blocking CI job with at least: size-limit per entry, Lighthouse CI score and LCP deltas, and a bundle-diff check that flags new dependencies above a threshold. Post-deploy RUM regression triggers a rollback per deployment-release-engineering. Full workflow in references/budgets-and-regression-gate.md.
Working reference material
- Loading-path tactics (images, JS, CSS, fonts, hints, compression):
references/loading-performance.md.
- Rendering, CLS, and INP mechanics:
references/rendering-and-inp.md.
- Framework recipes (React, Next.js App Router, Vue, vanilla, service workers):
references/framework-recipes.md.
Anti-patterns
- Global budget for the whole app. Before: "JS < 200KB". After: per-flow budget with device class, e.g. "Product listing on Moto G Power, 4G: JS < 200KB, LCP p75 < 2.2s". A flat global budget lets heavy flows hide behind light ones.
- Anti-patterns as principles, not mechanics. Before: "Avoid tight coupling between UI and API". After: "Do not
await sequential API calls inside a server component that blocks streaming — use Promise.all or move non-critical data to a <Suspense> boundary". Concrete fix, concrete diagnostic.
- Lighthouse score as the sole KPI. Before: "We target Lighthouse 90+ on PRs". After: Lighthouse CI is one lane in the gate; field LCP/INP/CLS p75 drive the alerting contract. Lab-only optimisation masks real-user regressions on low-end devices.
- Lazy-loading the LCP image. Before:
<img src="hero.jpg" loading="lazy">. After: <img src="hero.jpg" loading="eager" fetchpriority="high" width=... height=...> plus <link rel="preload" as="image" ...> when the hero is below the HTML discoverability point.
- Animating layout-triggering properties. Before:
transition: width 300ms on a sidebar. After: transition: transform 300ms with the sidebar off-canvas and translated in. Avoids forced layout on every frame.
- Regression gate that only warns. Before: CI job posts a comment with
size-limit delta. After: job fails the required check when any entry exceeds budget; baseline regeneration is a deliberate PR. Non-blocking gates decay within two sprints.
- Inventing frontend-only dashboards. Before: a bespoke Grafana board owned by the frontend team. After: SLIs published on the RUM dashboard defined by
observability-monitoring, with alert routing through the shared on-call pipeline.
- Preloading everything. Before: ten
<link rel="preload"> tags. After: preload only the LCP image and one critical font; everything else competes for bandwidth on the critical path.
Read next
skill-composition-standards — house-style and contract rules this skill conforms to.
observability-monitoring — owner of SLOs, RUM dashboard, and alert pipeline that the measurement plan plugs into.
system-architecture-design — source of the critical-flow table that budgets depend on.
react-development — React-specific patterns referenced by the framework recipes.
nextjs-app-router — Next.js App Router strategies for server components, streaming, and next/image.
References
references/budgets-and-regression-gate.md — the three deliverables in template form.
references/loading-performance.md — image, JS, CSS, font, and resource-hint detail.
references/rendering-and-inp.md — layout, paint, CLS, and INP mechanics.
references/framework-recipes.md — React, Next.js App Router, Vue, vanilla, service workers.
1---2name: frontend-performance3description: Use when defining, implementing, or auditing frontend performance for web apps and SaaS frontends; produces a per-flow performance budget, measurement plan tied to SLOs, and CI regression gate. Use api-design-first for API shape and observability-monitoring for server SLOs.4metadata:5 portable: true6 compatible_with:7 - claude-code8 - codex9---1011# Frontend Performance12Acknowledgement: Shared by Peter Bamuhigire, techguypeter.com, +256 784 464178.1314Specialist frontend skill. Produces the three deliverables that give a team an operable performance posture: a budget per critical flow, a measurement plan tied to the SLO set, and a regression gate in CI. Not a generic optimisation checklist.1516**Prerequisites:** Load `system-architecture-design` (for the critical-flow table) and `observability-monitoring` (for the SLO set and RUM dashboard conventions) before this skill. Load `react-development` or `nextjs-app-router` if the stack is React/Next.1718<!-- dual-compat-start -->19## Use When2021- Defining the performance budget for a new product or critical flow.22- Diagnosing a field regression on LCP, INP, or CLS captured by RUM.23- Wiring up a regression gate before a team scales frontend merges.24- Auditing an existing frontend and translating findings into budgets and gates.25- Choosing between inline CSS vs deferred, server vs client rendering, or route vs component code-split.2627## Do Not Use When2829- The bottleneck is server latency or database query time — use `observability-monitoring`, the relevant database skill, or `reliability-engineering`.30- The work is API contract design — use `api-design-first`.31- The work is pure visual/interaction design without a measurable performance cost — use the UI/UX baseline skills.3233## Required Inputs3435- Critical-flow table from `system-architecture-design`.36- SLO set and RUM dashboard conventions from `observability-monitoring`.37- Device and network mix for the target user base.3839## Workflow4041- Read this SKILL.md, then load `references/budgets-and-regression-gate.md` plus whichever of `loading-performance.md`, `rendering-and-inp.md`, `framework-recipes.md` the task requires.42- Produce the three deliverables (budget, measurement plan, regression gate) before chasing individual optimisations.43- Tie every SLI back to an SLO owned by `observability-monitoring`.4445## Quality Standards4647- Budget rows and SLIs map one-to-one with critical flows and SLOs; no orphan metrics.48- Gate is blocking in CI, not advisory.49- Field measurement (RUM) is primary; lab measurement is a leading indicator.5051## Anti-Patterns5253- Chasing Lighthouse score without a field measurement plan.54- Declaring a budget without naming the device class and network.55- Adding a regression gate that only warns and never blocks.5657## Outputs5859- Performance budget per critical flow.60- Measurement plan (SLIs, source, reporting surface, alert thresholds).61- Regression gate in CI.6263## Evidence Produced6465| Category | Artifact | Format | Example |66|----------|----------|--------|---------|67| Performance | Performance budget document | Markdown doc stating page, API, and interaction budgets | `docs/performance/budgets-checkout.md` |68| Performance | Real-user and synthetic metrics evidence | Dashboard link plus archived snapshot | `docs/performance/rum-snapshot-2026-04-16.md` |6970## Capability contract7172Read and search the application and measurement configuration first. Editing and execution require authorisation; when available, run the existing build, bundle analysis, lab checks, and relevant tests. Network access is optional for current browser guidance.7374- `references/budgets-and-regression-gate.md`75- `references/loading-performance.md`76- `references/rendering-and-inp.md`77- `references/framework-recipes.md`78<!-- dual-compat-end -->7980## When this skill applies8182- Establishing a performance budget for a new product or each critical flow in an existing product.83- Investigating a field regression in LCP, INP, or CLS flagged by RUM.84- Designing a CI regression gate before the team scales frontend merges.85- Auditing an existing frontend and producing budgets plus gates, not just a "make it faster" ticket list.86- Choosing between competing rendering strategies (SSR vs SSG vs CSR, inline vs deferred CSS, route vs component split).8788## Inputs8990| Artifact | Produced by | Required? | Why |91|---|---|---|---|92| Critical-flow table | `system-architecture-design` | required | Budgets are defined per critical flow, not per page |93| SLO set | `observability-monitoring` | required | Frontend SLIs must align with owned SLOs and alert pipelines |94| RUM dashboard conventions | `observability-monitoring` | required | Where field measurements are reported and alerted |95| Device + network mix | product/analytics | required | Determines the reference device class and throttling profile |96| API error model | `api-design-first` | optional | Informs retry + fallback UI budget |97| Threat model | `vibe-security-skill` | optional | Gates CSP and third-party script decisions |9899## Outputs100101| Artifact | Consumed by | Template |102|---|---|---|103| Performance budget per critical flow | `deployment-release-engineering`, `observability-monitoring`, QA | `references/budgets-and-regression-gate.md` |104| Measurement plan (SLIs, sources, reporting, thresholds) | `observability-monitoring`, on-call | `references/budgets-and-regression-gate.md` |105| Regression gate in CI | `cicd-pipelines`, `deployment-release-engineering` | `references/budgets-and-regression-gate.md` |106| Framework recipe notes | `react-development`, `nextjs-app-router`, Vue/Nuxt specialists | `references/framework-recipes.md` |107108## Non-negotiables109110- A budget is stated per critical flow with an explicit device class and network.111- Every SLI maps to an SLO owned by `observability-monitoring`; no stand-alone frontend dashboards.112- Regression gate blocks merges when thresholds are breached; it is not advisory.113- Field measurements (`web-vitals` beaconed to RUM) drive alerting. Lab metrics (Lighthouse CI) are a PR leading indicator only.114- Core Web Vitals targets: LCP p75 < 2.5s, INP p75 < 200ms, CLS p75 < 0.1 — unless a flow-specific budget supersedes them with written justification.115116## Decision rules117118### Rendering strategy119120```text121Mostly static marketing / docs / blog -> SSG (or ISR with long revalidate)122Authenticated dashboard, per-user data -> SSR streaming + client islands123Highly interactive tool (editor, canvas) -> CSR with aggressive code-split124Tenant-scoped SaaS app, mixed criticality -> Server components + selective client125126Wrong choice failure mode:127- SSG for per-user data -> stale personalisation, auth leaks across caches128- SSR for heavy interactivity -> slow TTFB, wasted server render on cold data129- CSR for content-first pages -> poor LCP, poor SEO130```131132### Inline CSS vs deferred133134```text135Above-fold critical path, < 14KB critical CSS -> inline in <head>136Route-specific, bulky, cachable -> external file, async preload137Third-party widget CSS (chat, analytics UI) -> defer, load after interaction138Design tokens / reset / typography base -> inline (tiny, load-blocking is fine)139140Wrong choice failure mode:141- Inline everything -> bloated HTML, no CSS caching across navigations142- Defer critical styles -> FOUC and layout shift on first paint143```144145### Code splitting strategy146147```text148Route-based split -> default for every SPA/Next route149Component-level dynamic import -> heavy widget (editor, chart, map) > 30KB150Vendor split (react/react-dom) -> long-cache chunk, rarely updated151No split -> only for single-page tools under 150KB total152153Wrong choice failure mode:154- Over-splitting tiny chunks -> HTTP request overhead + waterfall155- Single monolithic bundle -> blocks initial interactivity, poor INP156```157158### Image handling159160```text161Hero / LCP candidate -> eager, fetchpriority=high, preload162Above fold, non-LCP -> eager, default priority163Below fold -> loading=lazy, decoding=async164Vector/icon under 2KB -> inline SVG (no request)165Repeat background -> CSS background with responsive image-set()166167Wrong choice failure mode:168- Lazy-loading LCP -> catastrophic LCP regression169- Eager-loading below fold -> bandwidth waste, contention with LCP170```171172### When to add a new SLI173174```text175Metric exists and alert correlates with user-visible harm -> keep, publish on dashboard176Metric is a proxy with no known user impact -> do not alert, log for investigation177Metric is a per-flow variant of a global SLI -> add as dimension, not new SLI178Metric overlaps a backend SLO -> owned by observability-monitoring, not here179```180181## Core content182183The three deliverables below are the contract. Everything else in `references/` supports producing them.184185### 1. Performance budget per critical flow186187For each row in the upstream critical-flow table, declare: target device class, target network, LCP, INP, CLS, compressed JS, compressed CSS, total compressed transfer, image-LCP cap. Example table and rules: `references/budgets-and-regression-gate.md`.188189### 2. Measurement plan190191For every SLI: the source (field or lab), the beacon/collector, the dashboard where it is reported, and the alert threshold. Field measurements use `web-vitals` JS beaconed to the RUM backend defined by `observability-monitoring`. Lab measurements use Lighthouse CI in the merge pipeline.192193### 3. Regression gate194195A blocking CI job with at least: `size-limit` per entry, Lighthouse CI score and LCP deltas, and a bundle-diff check that flags new dependencies above a threshold. Post-deploy RUM regression triggers a rollback per `deployment-release-engineering`. Full workflow in `references/budgets-and-regression-gate.md`.196197### Working reference material198199- Loading-path tactics (images, JS, CSS, fonts, hints, compression): `references/loading-performance.md`.200- Rendering, CLS, and INP mechanics: `references/rendering-and-inp.md`.201- Framework recipes (React, Next.js App Router, Vue, vanilla, service workers): `references/framework-recipes.md`.202203## Anti-patterns204205- **Global budget for the whole app.** Before: "JS < 200KB". After: per-flow budget with device class, e.g. "Product listing on Moto G Power, 4G: JS < 200KB, LCP p75 < 2.2s". A flat global budget lets heavy flows hide behind light ones.206- **Anti-patterns as principles, not mechanics.** Before: "Avoid tight coupling between UI and API". After: "Do not `await` sequential API calls inside a server component that blocks streaming — use `Promise.all` or move non-critical data to a `<Suspense>` boundary". Concrete fix, concrete diagnostic.207- **Lighthouse score as the sole KPI.** Before: "We target Lighthouse 90+ on PRs". After: Lighthouse CI is one lane in the gate; field LCP/INP/CLS p75 drive the alerting contract. Lab-only optimisation masks real-user regressions on low-end devices.208- **Lazy-loading the LCP image.** Before: `<img src="hero.jpg" loading="lazy">`. After: `<img src="hero.jpg" loading="eager" fetchpriority="high" width=... height=...>` plus `<link rel="preload" as="image" ...>` when the hero is below the HTML discoverability point.209- **Animating layout-triggering properties.** Before: `transition: width 300ms` on a sidebar. After: `transition: transform 300ms` with the sidebar off-canvas and translated in. Avoids forced layout on every frame.210- **Regression gate that only warns.** Before: CI job posts a comment with `size-limit` delta. After: job fails the required check when any entry exceeds budget; baseline regeneration is a deliberate PR. Non-blocking gates decay within two sprints.211- **Inventing frontend-only dashboards.** Before: a bespoke Grafana board owned by the frontend team. After: SLIs published on the RUM dashboard defined by `observability-monitoring`, with alert routing through the shared on-call pipeline.212- **Preloading everything.** Before: ten `<link rel="preload">` tags. After: preload only the LCP image and one critical font; everything else competes for bandwidth on the critical path.213214## Read next215216- `skill-composition-standards` — house-style and contract rules this skill conforms to.217- `observability-monitoring` — owner of SLOs, RUM dashboard, and alert pipeline that the measurement plan plugs into.218- `system-architecture-design` — source of the critical-flow table that budgets depend on.219- `react-development` — React-specific patterns referenced by the framework recipes.220- `nextjs-app-router` — Next.js App Router strategies for server components, streaming, and `next/image`.221222## References223224- `references/budgets-and-regression-gate.md` — the three deliverables in template form.225- `references/loading-performance.md` — image, JS, CSS, font, and resource-hint detail.226- `references/rendering-and-inp.md` — layout, paint, CLS, and INP mechanics.227- `references/framework-recipes.md` — React, Next.js App Router, Vue, vanilla, service workers.