agentleFS
vindreshsinghvindreshsingh/engineering-skills/skills/perf-budget/SKILL.md

perf-budget

Skill0 starsChanged 5 months agoMITView on GitHub

Optimizes performance by measuring first and fixing the real bottleneck. Use when something is slow, before optimizing, when setting latency or bundle targets, or reviewing changes for performance traps — not for speculative micro-tuning.

6 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use doc-sync.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • JetBrainsSkill

    doc-sync

    Keeps IdeaVim documentation in sync with code changes. Use this skill when you need to verify documentation accuracy after code changes, or when checking if documentation (in doc/, README.md, CONTRIBUTING.md) matches the current codebase. The skill can work bidirectionally - from docs to code verification, or from code changes to documentation updates.

    Also in 3 projects that use this

The file

Show its rules and text

We split this skill into the rules it gives an agent

13 rules. 0 are common, 13 are distinctive, and 0 are very specific to this project.

  • 0

    Common

    Most of the 5 edited versions we read keep these.

  • 13

    Distinctive

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Run the performance checklist alongside this process for common traps — only after you've confirmed the path is hot.

    line 16
  2. Distinctive:

    After a launch when latency or error budget regressed ([[launch-readiness]])

    line 27
  3. Distinctive:

    Don't demand perf work on every PR — apply when the path is hot or the budget is at risk.

    line 30
  4. Distinctive:

    Write the target before profiling:

    line 40
  5. Distinctive:

    Ask: what single change would move the budget most?

    line 90
  6. Distinctive:

    If multiple similar costs, fix the easiest high-impact first — sometimes parallelizing two 200ms calls beats optimizing one 50ms call.

    line 106
  7. Distinctive:

    One change at a time: when validating — or isolate in benchmark — so you know what moved the number ([[fault-recovery]] discipline).

    line 127
  8. Distinctive:

    After each meaningful change:

    line 132
  9. Distinctive:

    Check regressions elsewhere — faster checkout but 2× DB load?

    line 136
  10. Distinctive:

    Don't keep "optimizations" that profiler can't justify.

    line 143
  11. Distinctive:

    Document before/after in PR — reviewers and future-you need proof.

    line 145
  12. Distinctive:

    Every perf win can cost something — name it:

    line 149
  13. Distinctive:

    No before/after numbers in PR

    line 236

“Common” is measured: kept by at least 6 in 10 of the 5 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Perf Budget

Performance work starts with a number and a measurement, not a hunch. Set a budget, profile the real workload, fix the dominant cost, measure again, and add a guard so regression can't sneak back. Optimizing the wrong layer — micro-tuning a cold path while N+1 queries dominate — wastes effort and adds complexity.

A perf budget is an explicit target: p95 latency, bundle kilobytes, query time, memory ceiling. Without one, "faster" is unmeasurable and every optimization is premature.

Run the performance checklist alongside this process for common traps — only after you've confirmed the path is hot. Pair with [[observability]] for production numbers, [[data-modeling]] for query/index work, [[caching-strategy]] only after read cost is measured, [[react-patterns]] for React/Next.js specifics, and [[browser-checks]] for perceived slowness in the UI.

When to Use

  • A page, API, query, job, or interaction is measurably slow
  • Setting or enforcing targets — SLOs, bundle budgets, CI perf gates
  • Before optimizing — confirm where time actually goes
  • Reviewing PRs for obvious traps ([[review-gate]]) — N+1, waterfalls, unbounded work
  • After a launch when latency or error budget regressed ([[launch-readiness]])

Skip micro-optimization on cold paths, one-time setup, or code with no user-facing latency impact. Don't demand perf work on every PR — apply when the path is hot or the budget is at risk.

Not a substitute for [[caching-strategy]] — measure first; cache only when read cost justifies it.

Process

Work in order. No code changes until you have a baseline number.

1. Define the budget — make "fast" concrete

Write the target before profiling:

SurfaceExample budgets
APIp95 < 200ms, p99 < 500ms for POST /orders
PageLCP < 2.5s, TTI < 3s on 4G ([[browser-checks]])
Query< 50ms p95 at 10M rows; examines < 1% of table
JobProcess 10k msgs/min; p95 handle < 2s
BundleMain chunk < 200KB gzip; route chunk < 80KB
MemoryWorker steady < 512MB under peak load

Include:

  • Metric — what (latency, size, throughput)
  • Statistic — p50 vs p95 vs p99 (tail matters for UX)
  • Workload — realistic data volume, concurrency, payload size
  • Environment — prod-like, not empty dev DB

Align with SLOs in [[observability]] — perf budgets feed alerts and error budgets.

Bad:  "Checkout should be fast"
Good: "POST /orders p95 < 500ms at 100 RPS, prod-like cart (20 items)"

2. Measure baseline — production truth beats guesswork

Prefer production or prod-like measurements ([[observability]]):

  • APM traces — p95/p99 per endpoint, span breakdown
  • DB slow query log, EXPLAIN ANALYZE on realistic volume ([[data-modeling]])
  • Browser Performance tab, Lighthouse, Web Vitals ([[browser-checks]])
  • Load test at expected concurrency — find saturation, not just single-request time

Profile the dominant path:

LayerTools / signals
BackendTrace waterfall, CPU profiler, flame graph
DatabaseQuery plan, rows examined vs returned, lock wait
FrontendNetwork waterfall, React profiler, bundle analyzer
BatchPer-stage timing, queue lag

Record baseline numbers in the ticket/PR — you'll need them for after.

Intuition is wrong — the slow function you remember is often 2% of request time; one unindexed query or serial await chain is the real killer.

3. Find the bottleneck — one dominant cost

Ask: what single change would move the budget most?

Rank costs from profile/trace:

POST /orders p95 840ms breakdown (example):
  payment API     520ms  ← dominant
  DB insert        45ms
  tax calculation  12ms
  JSON serialize    3ms

Fix payment first — not JSON. Shaving 1ms off serialize when payment is 520ms is waste.

Hot path check — does this code run per request at scale? One-off admin export ≠ checkout API.

If multiple similar costs, fix the easiest high-impact first — sometimes parallelizing two 200ms calls beats optimizing one 50ms call.

4. Fix structural wins before micro-optimizations

Priority order (stop when budget met):

PriorityWinSkills
1Remove N+1; batch/join queries[[data-modeling]]
2Add/fix indexes for real query patterns[[data-modeling]]
3Parallelize independent I/O; kill waterfalls[[react-patterns]]
4Paginate/limit unbounded work[[data-modeling]]
5Algorithm fix — O(n²) → O(n), better structure[[simplify]]
6Cache expensive measured reads[[caching-strategy]]
7Lazy load / split bundle[[react-patterns]]
8Micro-tune hot loopOnly with profiler proof

Caching last among structural options — confirm read cost on hot path first ([[caching-strategy]]). A better query often removes the need entirely.

One change at a time when validating — or isolate in benchmark — so you know what moved the number ([[fault-recovery]] discipline).

5. Measure again — prove it worked or revert

After each meaningful change:

  • Re-run same workload / benchmark / trace comparison
  • Compare same statistic (p95, not p50 only)
  • Check regressions elsewhere — faster checkout but 2× DB load?
Before: p95 840ms | After: p95 310ms | Budget: 500ms ✓

If the number didn't move — revert the change unless it bought clarity or mandatory fix. Don't keep "optimizations" that profiler can't justify.

Document before/after in PR — reviewers and future-you need proof.

6. Account for trade-offs — speed isn't free

Every perf win can cost something — name it:

OptimizationTrade-off
CacheStaleness, invalidation bugs ([[caching-strategy]])
ParallelismConnection pool pressure, harder debugging
DenormalizationWrite complexity, consistency ([[data-modeling]])
Aggressive bundlingCacheability, deploy granularity
Lower samplingLess observability detail

Spend complexity only where measurement shows user-visible gain. A 5ms win on a 2s page isn't worth opaque code.

7. Add guards — prevent silent regression

Lock the win:

GuardWhen
Benchmark in CICritical pure logic; threshold assert
Bundle size budgetFrontend CI fails if chunk grows > X KB
Load test gateRelease pipeline p95 check ([[pipeline-ops]])
SLO alertProduction p95 regression ([[observability]])
Query plan checkEXPLAIN in test on representative query

Guards should match the same metric you optimized — not a different proxy that drifts.

Re-baseline when workload changes — budgets aren't forever.

8. Layer-specific playbooks

Slow API endpoint

Trace → rank spans → N+1 / missing index / external call → fix dominant → re-trace → SLO alert.

Slow SQL

EXPLAIN ANALYZE on prod stats → rows examined → index or rewrite → measure at volume ([[data-modeling]]).

Slow page load

Network waterfall → LCP element → bundle size + critical path → lazy load / server fetch parallel ([[react-patterns]], [[browser-checks]]).

Slow React interaction

Profiler → unnecessary re-renders vs expensive render → fix render or defer work → 60fps input check.

Background job behind

Queue depth + per-message timing → slow handler step → batch DB writes → throughput metric.

"Feels slow" user report

Reproduce with trace → compare p95 vs p50 (tail issue?) → [[browser-checks]] on real device/network.

Pre-launch perf pass ([[launch-readiness]])

Define budget → load test staging → fix blockers → dashboard + alert before 100% ramp.

9. When NOT to optimize

  • Cold path (admin export once a day)
  • Already within budget with headroom
  • Hypothetical scale ("might have 1M users someday") without current pain
  • Readability collapse for unmeasured micro-gains
  • Caching before measuring read cost
  • Optimizing staging with 3 rows when prod has 10M

Ship the feature; measure in prod; optimize what prod proves is slow ([[observability]]).

Common Rationalizations

  • "This code is obviously the slow part." — Profile it; obvious culprits are often innocent.
  • "Micro-optimizing can't hurt." — Complexity and risk without measured gain hurts maintainability.
  • "We don't have time to measure." — Less time than optimizing the wrong thing twice.
  • "Add a cache, it'll be faster." — Measure first; invalidation bugs cost more than slow reads.
  • "p50 looks fine." — Users hit p99 tail; tail is UX for many flows.
  • "Staging was fast enough." — Data volume and concurrency differ in prod.
  • "We'll add perf tests later." — Regressions ship in the meantime.
  • "Parallel always helps." — Pool exhaustion and contention can slow the system.

Red Flags

  • Optimizing before profiling or tracing
  • Fixing cold path while hot path still over budget
  • No before/after numbers in PR
  • Cache added without measured read cost or invalidation ([[caching-strategy]])
  • N+1 or full table scan visible in trace — unaddressed
  • Bundle grew with no budget check
  • Micro-optimization with no profiler evidence
  • Load test never run before high-tier launch
  • p50 cited when users complain about sporadic slowness
  • Perf "fix" that increases error rate or memory without acknowledgment
  • CI perf guard disabled to green the build

Verification

  • Concrete budget defined — metric, statistic, workload, environment
  • Baseline measured on hot path — trace/profile/query plan, not guesswork ([[observability]])
  • Dominant bottleneck identified and fixed first (structural before micro)
  • Performance checklist applied to changed hot paths
  • Before/after numbers documented; budget met or explicit acceptance of gap
  • Trade-offs named — cache, parallelism, consistency, complexity
  • Regression guard added or existing SLO/alert covers the metric ([[pipeline-ops]])
  • Caching only if read cost measured and invalidation designed ([[caching-strategy]])
  • Frontend: bundle and interaction checked if UI path ([[react-patterns]], [[browser-checks]])

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.