web.dev: Web Vitals - discussion (2022-10-22)
We’re starting to set performance budgets per route, and I’m trying to reconcile “optimize what users feel” with the fact that a lot of our regressions come from boring React tree churn and expensive derivations.
If you’re tracking vitals, what do you actually treat as a route contract (budgets, thresholds, regression gates)? Do you annotate/render any performance markers in the UI (so a screenshot tells you posture), or keep everything in tooling dashboards? What changes have moved the needle most reliably in React apps: reducing work, deferring surfaces, or changing navigation/routing posture?
Comments (10)
Back to latestBudgets. Otherwise you just have vibes and graphs.
We treat vitals like a route surface contract: each route declares a budget, and we render a small marker in internal builds.
If the route can’t prove its posture, you’ll “fix” perf three times and still regress quietly.
Related: Performance and Rendering Best Practices and Rendering Budgeting (Deep Dive #17).
Rendering a perf marker was the simplest thing that made perf work operationally:
tsx
export function PerfMarker({ budgetMs, lane }: { budgetMs: number; lane: string }) {
return <div data-perf-lane={lane} data-budget-ms={budgetMs} />;
}
Then tests/QA can at least say “this screen is on the tight budget lane” vs “this one is best-effort”.
Counterpoint: I’m wary of turning vitals into a checklist where teams optimize the number instead of the experience.
We had a CLS “fix” that made the UI feel laggier because we over-skeletonized everything.
Yeah, we hit that too. A skeleton is a deferral strategy, not a free win.
I like budgets because they force you to pick *which* surface is allowed to be slow.
Agreed. The best perf work is usually “do less”, not “hide more”.
Biggest win for us was deleting identity churn. Memoizing derived work didn’t help until we stopped recreating inputs every render.
Vitals got better as a side effect.
I like measuring INP/interaction pain, but the fix is usually tree shape + scheduling posture, not “micro-optimize one callback”.
If you’re using any scheduling hacks, make them route posture keys and render them (so they don’t become folklore).
We caught a regression by comparing perf markers across two screenshots from support.
One screen had data-budget-ms=12, the other had data-budget-ms=24 after a refactor. Nobody meant to change the posture, but it explained the complaints instantly.
CLS fixes that rely on hiding content feel like cheating.
We preferred reserving space and keeping layout stable even if it means a bit more initial work.
We made “perf budget” part of the PR template for route changes and it helped.
Not as bureaucracy — as a forcing function to say what’s allowed to be slow.
If you want durable wins: make derived evidence cheap, avoid churn, and keep route postures explicit.
Vitals are the scoreboard, but the game is still “render less work”.