Node.js Performance
Use this workflow to turn Node.js performance/resource investigations into safe, reviewable PRs.
Goals
- Improve execution time first: reduce p50/p95/p99 latency and increase throughput without changing intended behavior.
- Reduce CPU, memory, event-loop lag, I/O pressure, or lock contention when it supports execution-time gains.
- Ship small, isolated changes with measurable impact.
Operating Rules
- Work on one optimization per PR.
- Always choose the highest expected-impact task first.
- Confirm and respect intentional behaviors before changing them.
- Prefer low-risk changes in high-frequency paths.
- Prioritize request/job execution-path work over bootstrap/startup micro-optimizations unless startup is on the critical path at scale.
- Include evidence: targeted tests + before/after benchmark.
Impact-First Selection
Before coding, rank candidates using this score:
priority = (frequency x blast_radius x expected_gain) / (risk x effort)
Use 1-5 for each factor:
frequency: how often the path runs in production.
blast_radius: how many requests/jobs/users are affected.
expected_gain: estimated latency/resource improvement.
risk: probability of behavior regression.
effort: engineering time and change surface area.
Pick the top-ranked candidate, then validate with a baseline measurement.
If two candidates have similar score, pick the one with clearer end-to-end execution-time impact.
Prioritization Targets
Start with code that runs on every request/job/task:
- Request/job wrappers and middleware.
- Retry/timeout/circuit-breaker code.
- Connection pools (DB/Redis/HTTP) and socket reuse.
- Stream/pipeline transformations and buffering.
- Serialization/deserialization hot paths (JSON, parsers, schema validation).
- Queue consumers, schedulers, and worker dispatch.
- Event listener attach/detach lifecycle and cleanup logic.
Deprioritize unless justified by production profile:
- One-time startup/bootstrap code.
- Rare admin/debug-only flows.
- Teardown paths that are not on the steady-state critical path.
Common Hot-Path Smells
- Recomputing invariant values per invocation.
- Re-parsing code/AST repeatedly.
- Duplicate async lookups returning the same value.
- Per-call heavy object allocation in common-case parsing.
- Unnecessary awaits in teardown/close/dispose paths.
- Missing fast paths for dominant input shapes.
- Unbounded retries or retry storms under degraded dependencies.
- Excessive concurrency causing memory spikes or downstream saturation.
- Work done for logging/telemetry/metrics formatting even when disabled.
Execution Workflow
- Pick one candidate
- Rank candidates and pick the highest priority score.
- Explain the issue in one sentence.
- State expected impact (CPU, latency, memory, event-loop lag, I/O, contention).
- Prove it is hot
- Add a focused micro-benchmark or scenario benchmark.
- Capture baseline numbers before editing.
- Prefer scenario benchmarks that include real request/job flow when the goal is execution-time improvement.
- For resource issues, capture process metrics (
rss, heap, FD count, event-loop delay).
- Design minimal fix
- Keep behavior-compatible defaults.
- Add fallback path for edge cases.
- Avoid broad refactors in the same PR.
- Implement
- Make the smallest patch that removes repeated work.
- Keep interfaces stable unless change is necessary.
- Test
- Add/adjust targeted tests for new behavior and regressions.
- Run relevant package tests (not only whole-monorepo by default).
- Add concurrency/degradation tests when the bug appears only under load.
- Benchmark again
- Re-run the same benchmark with same parameters.
- Report absolute and relative deltas.
- Include latency deltas first (p50/p95/p99, throughput), then resource deltas when applicable.
- Package PR
- Branch naming:
codex/perf-<area>-<change>.
- Commit message:
perf(<package>): <what changed>.
- Include risk notes and rollback simplicity.
- Iterate
- Wait for review, then move to next isolated improvement.
Benchmarking Guidance
- Keep benchmark scope narrow to isolate one change.
- Use warmup iterations.
- Measure both:
micro: operation-level overhead.
scenario: request/job flow, concurrency, and degraded dependency condition.
- For execution-time work, scenario numbers are the decision-maker; micro numbers are supporting evidence.
- Always print:
- total time
- per-op time
- p50/p95/p99 latency when applicable
- speedup ratio
- iterations and workload shape
- resource counters (
rss, heap, handles, event-loop delay) when relevant
Resource Exhaustion Checklist
- Cap concurrency at each boundary (ingress, queue, downstream clients).
- Ensure timeout + cancellation are wired end-to-end.
- Ensure retries are bounded and jittered.
- Confirm listeners/timers/intervals are always cleaned up.
- Confirm streams are closed/destroyed on success and error paths.
- Confirm object caches have size/TTL controls.
CI / Flake Handling
- If CI-only failures appear, add temporary diagnostic payloads in tests.
- Serialize only affected flaky tests when resource contention is the cause.
- Keep determinism improvements in test code, not production code, unless required.
Output Template
For each PR, report:
- Issue being fixed.
- Why it matters under load.
- Code locations changed.
- Tests run and results.
- Benchmark before/after numbers (execution first: p50/p95/p99 and throughput).
- Risk assessment.
- Next candidate optimization.
1---2name: nodejs-performance3description: Optimize Node.js latency, p50/p95/p99, throughput, CPU, memory, event-loop lag, FD pressure, retries, and benchmarks one PR at a time.4---56# Node.js Performance78Use this workflow to turn Node.js performance/resource investigations into safe, reviewable PRs.910## Goals1112- Improve execution time first: reduce p50/p95/p99 latency and increase throughput without changing intended behavior.13- Reduce CPU, memory, event-loop lag, I/O pressure, or lock contention when it supports execution-time gains.14- Ship small, isolated changes with measurable impact.1516## Operating Rules1718- Work on one optimization per PR.19- Always choose the highest expected-impact task first.20- Confirm and respect intentional behaviors before changing them.21- Prefer low-risk changes in high-frequency paths.22- Prioritize request/job execution-path work over bootstrap/startup micro-optimizations unless startup is on the critical path at scale.23- Include evidence: targeted tests + before/after benchmark.2425## Impact-First Selection2627Before coding, rank candidates using this score:2829`priority = (frequency x blast_radius x expected_gain) / (risk x effort)`3031Use 1-5 for each factor:3233- `frequency`: how often the path runs in production.34- `blast_radius`: how many requests/jobs/users are affected.35- `expected_gain`: estimated latency/resource improvement.36- `risk`: probability of behavior regression.37- `effort`: engineering time and change surface area.3839Pick the top-ranked candidate, then validate with a baseline measurement.4041If two candidates have similar score, pick the one with clearer end-to-end execution-time impact.4243## Prioritization Targets4445Start with code that runs on every request/job/task:4647- Request/job wrappers and middleware.48- Retry/timeout/circuit-breaker code.49- Connection pools (DB/Redis/HTTP) and socket reuse.50- Stream/pipeline transformations and buffering.51- Serialization/deserialization hot paths (JSON, parsers, schema validation).52- Queue consumers, schedulers, and worker dispatch.53- Event listener attach/detach lifecycle and cleanup logic.5455Deprioritize unless justified by production profile:5657- One-time startup/bootstrap code.58- Rare admin/debug-only flows.59- Teardown paths that are not on the steady-state critical path.6061## Common Hot-Path Smells6263- Recomputing invariant values per invocation.64- Re-parsing code/AST repeatedly.65- Duplicate async lookups returning the same value.66- Per-call heavy object allocation in common-case parsing.67- Unnecessary awaits in teardown/close/dispose paths.68- Missing fast paths for dominant input shapes.69- Unbounded retries or retry storms under degraded dependencies.70- Excessive concurrency causing memory spikes or downstream saturation.71- Work done for logging/telemetry/metrics formatting even when disabled.7273## Execution Workflow74751. **Pick one candidate**76- Rank candidates and pick the highest priority score.77- Explain the issue in one sentence.78- State expected impact (CPU, latency, memory, event-loop lag, I/O, contention).79802. **Prove it is hot**81- Add a focused micro-benchmark or scenario benchmark.82- Capture baseline numbers before editing.83- Prefer scenario benchmarks that include real request/job flow when the goal is execution-time improvement.84- For resource issues, capture process metrics (`rss`, heap, FD count, event-loop delay).85863. **Design minimal fix**87- Keep behavior-compatible defaults.88- Add fallback path for edge cases.89- Avoid broad refactors in the same PR.90914. **Implement**92- Make the smallest patch that removes repeated work.93- Keep interfaces stable unless change is necessary.94955. **Test**96- Add/adjust targeted tests for new behavior and regressions.97- Run relevant package tests (not only whole-monorepo by default).98- Add concurrency/degradation tests when the bug appears only under load.991006. **Benchmark again**101- Re-run the same benchmark with same parameters.102- Report absolute and relative deltas.103- Include latency deltas first (p50/p95/p99, throughput), then resource deltas when applicable.1041057. **Package PR**106- Branch naming: `codex/perf-<area>-<change>`.107- Commit message: `perf(<package>): <what changed>`.108- Include risk notes and rollback simplicity.1091108. **Iterate**111- Wait for review, then move to next isolated improvement.112113## Benchmarking Guidance114115- Keep benchmark scope narrow to isolate one change.116- Use warmup iterations.117- Measure both:118- `micro`: operation-level overhead.119- `scenario`: request/job flow, concurrency, and degraded dependency condition.120- For execution-time work, scenario numbers are the decision-maker; micro numbers are supporting evidence.121- Always print:122- total time123- per-op time124- p50/p95/p99 latency when applicable125- speedup ratio126- iterations and workload shape127- resource counters (`rss`, heap, handles, event-loop delay) when relevant128129## Resource Exhaustion Checklist130131- Cap concurrency at each boundary (ingress, queue, downstream clients).132- Ensure timeout + cancellation are wired end-to-end.133- Ensure retries are bounded and jittered.134- Confirm listeners/timers/intervals are always cleaned up.135- Confirm streams are closed/destroyed on success and error paths.136- Confirm object caches have size/TTL controls.137138## CI / Flake Handling139140- If CI-only failures appear, add temporary diagnostic payloads in tests.141- Serialize only affected flaky tests when resource contention is the cause.142- Keep determinism improvements in test code, not production code, unless required.143144## Output Template145146For each PR, report:1471481. Issue being fixed.1492. Why it matters under load.1503. Code locations changed.1514. Tests run and results.1525. Benchmark before/after numbers (execution first: p50/p95/p99 and throughput).1536. Risk assessment.1547. Next candidate optimization.