Node.js Best Practices
Overview
This skill preserves the upstream intent: teach operators how to make sound Node.js decisions instead of copying fashionable patterns.
In this curated form, the skill is optimized for analysis and review of Node.js codebases, services, workers, CLIs, and internal tooling. It is especially useful when you need to assess:
- runtime and release-line fit
- event-loop safety and async correctness
- framework necessity versus built-in platform features
- dependency and supply-chain discipline
- testing, diagnostics, and observability maturity
- security posture and operational readiness
This is a decision-making skill, not a code-generation template. Use it to produce a justified review, recommendation, or architecture direction.
When to Use
Use this skill when:
- a team asks whether a Node.js service is production-ready
- you need to review architecture, framework choice, or async patterns
- a repository shows latency spikes, blocking work, or unstable concurrency behavior
- you need to judge whether built-in Node features can replace unnecessary dependencies
- you need a structured review of security, testing, diagnostics, or release hygiene
- the user wants best practices with rationale, trade-offs, and review criteria
Do not use this skill as the primary workflow when:
- the task is language-agnostic and not meaningfully Node-specific
- the user only wants implementation code with no review or architecture component
- the dominant problem is infrastructure-only and not connected to Node runtime behavior
- the codebase is browser-only JavaScript with no Node runtime concerns
Workflow
Establish the review target
- Identify whether the subject is an API server, CLI, worker, monolith, library, or mixed repository.
- Record the Node version policy from
.nvmrc, .node-version, package.json, CI config, Dockerfile, or deployment manifests.
- Confirm whether the question is about architecture, correctness, performance, security, or release readiness.
Map runtime responsibilities
- Separate I/O-bound work from CPU-bound work.
- Note where the process handles HTTP, queues, cron jobs, file I/O, streams, child processes, or crypto/compression.
- Flag any work that appears likely to block the event loop.
Review platform-fit decisions
- Check whether the codebase uses built-in capabilities appropriately before adding dependencies.
- Look for valid use of modern Node facilities such as
node:test, AsyncLocalStorage, diagnostics_channel, built-in fetch, --env-file, and permissions where relevant.
- Challenge framework or library choices that add abstraction without solving a concrete problem.
Assess correctness and maintainability
- Review async boundaries, error propagation, cancellation, shutdown behavior, and timeouts.
- Check whether configuration is explicit, validated, and environment-specific.
- Verify that modules, services, and adapters are separated cleanly enough to test and replace.
Assess dependency and supply-chain discipline
- Review lockfile presence, install reproducibility, dependency sprawl, and package freshness.
- Prefer
npm ci-style reproducible installs in CI over drift-prone install flows.
- Check whether dependency risk is controlled with minimal package count, provenance-aware publishing or consumption where applicable, and actionable audit handling rather than blind upgrades.
Assess testing and diagnostics
- Check whether tests cover behavior at the right level: unit, integration, contract, and failure-path tests.
- Look for observability support: structured logs, request or job correlation, health signals, metrics hooks, and useful crash diagnostics.
- Review whether production debugging relies on stable mechanisms instead of ad hoc
console.log sprawl.
Assess operational safety
- Review input validation, secret handling, permissions, file-system scope, subprocess usage, and network exposure.
- Confirm graceful shutdown, backpressure handling, and retry logic do not create duplicate work or data corruption.
- Check whether defaults are safe under failure, not only under happy-path traffic.
Produce a decision-oriented output
- Summarize findings as keep, change, or investigate.
- Prioritize by impact: correctness and security first, then operability, then maintainability.
- Recommend the smallest safe change that materially improves the system.
Review Output Format
Use this structure when presenting results:
- Context: what the service does and what Node is responsible for
- Strengths: practices worth preserving
- Critical risks: issues that can cause outages, corruption, or security exposure
- Important improvements: changes that improve resilience or clarity
- Optional refinements: nice-to-have improvements with lower urgency
- Decision summary: whether the current approach is acceptable, conditionally acceptable, or should be changed
Examples
Example 1: Short review summary
Target: Express-based internal API on Node 22
Decision: Conditionally acceptable
Strengths:
- Uses LTS runtime in CI and production
- Has a lockfile and reproducible CI install
- Uses structured logging and graceful shutdown hooks
Critical risks:
- Image processing runs inline on request path and blocks the event loop
- Request timeouts are missing on outbound fetch calls
- Input validation is inconsistent across routes
Important improvements:
- Move CPU-heavy image work to a worker or separate service
- Wrap outbound I/O with explicit timeout and retry policy
- Centralize schema validation at the edge
Example 2: Framework challenge
Question: Should this small JSON API keep a large framework stack?
Observed facts:
- 12 routes, minimal middleware, no SSR, no plugin ecosystem dependency
- Most code is validation, auth checks, and data access
- Team cites convenience, not a hard technical requirement
Reasoned recommendation:
- Re-evaluate framework weight versus built-in HTTP support or a lighter server layer
- Keep the current framework only if it provides proven operational value such as standardized plugins, hooks, or team-wide conventions
- Do not rewrite purely for fashion; rewrite only if complexity reduction is measurable
For deeper worked examples, open:
examples/review-example.md
examples/decision-scenarios.md
Best Practices
Do
- Prefer current supported Node release lines and document the target runtime explicitly.
- Distinguish CPU-bound work from I/O-bound work before discussing performance.
- Use built-in platform features when they meet the requirement cleanly.
- Require explicit timeouts, cancellation strategy, and error handling for outbound I/O.
- Keep request handlers thin; move business rules into testable modules.
- Preserve correlation context across async boundaries when tracing request or job flow matters.
- Use reproducible installs and review dependency additions as architecture decisions, not convenience-only changes.
- Treat observability as part of correctness: if failures cannot be diagnosed, the system is not truly production-ready.
Do Not
- Recommend a framework because it is popular without tying it to delivery or operational benefit.
- Assume async code is safe just because it uses
await.
- Put compression, crypto, large JSON transforms, image manipulation, or heavy parsing directly on hot request paths without justification.
- Accept unbounded concurrency, unbounded queues, or unbounded payload handling.
- Add packages for features already provided adequately by Node unless the package clearly reduces risk or complexity.
- Treat
npm audit output as a mechanical upgrade queue; evaluate exploitability, reachability, and breakage risk.
- Rely on scattered environment variables with no validation or startup checks.
Troubleshooting
Symptoms: Latency spikes under moderate traffic, CPU rises sharply, and unrelated requests slow down.
Solution: Review for event-loop blocking work such as sync filesystem calls, large JSON parsing/stringifying, crypto/compression on the request path, regex backtracking, or CPU-heavy transforms. Move CPU-bound work to workers, queues, or another service boundary where justified.
Symptoms: The service appears "async" but still hangs or times out unpredictably.
Solution: Inspect outbound I/O for missing timeouts, retries without bounds, unresolved promises, and connection-pool exhaustion. Verify that every network call has explicit timeout behavior and failure handling.
Symptoms: Logs are present, but incidents are still hard to trace across requests or jobs.
Solution: Check whether correlation IDs or async context propagation are preserved consistently. Prefer structured logs and stable context propagation over ad hoc string logging.
Symptoms: CI passes, but production fails after dependency updates or environment changes.
Solution: Check for non-reproducible installs, weak lockfile discipline, runtime version drift, and configuration assumptions hidden in shell environments. Confirm that CI and production use the same Node major line and installation strategy.
Symptoms: Memory growth appears gradual and hard to reproduce.
Solution: Review long-lived caches, event listeners, stream lifecycle handling, and request-scoped state retained beyond completion. Check whether backpressure is ignored or whether large objects remain referenced in closures.
For a faster diagnosis matrix, open references/troubleshooting-matrix.md.
Additional Resources
references/review-criteria.md — Open this when you need a compact but concrete Node.js review checklist with decision criteria.
references/troubleshooting-matrix.md — Open this when symptoms are operational and you need likely causes plus targeted review checks.
examples/review-example.md — Open this when you need a worked example of a review with findings and prioritization.
examples/decision-scenarios.md — Open this when the user is asking "should we use X?" and you need scenario-based decisions.
Scope Notes
This skill favors judgment and review quality over style debates. The best output is usually not "rewrite everything," but "keep what is working, change the parts that create measurable risk, and justify each recommendation in Node-specific terms."
1---2name: nodejs-best-practices-v3-23description: Node.js Best Practices workflow skill. Use this skill when the user needs Node.js development principles and decision-making. Framework selection, async patterns, security, and architecture. Teaches thinking, not copying and the operator should preserve the upstream workflow, copied support files, and provenance before merging or handing off.4license: SEE LICENSE IN UPSTREAM SOURCE5---67# Node.js Best Practices89## Overview1011This skill preserves the upstream intent: teach operators how to make sound Node.js decisions instead of copying fashionable patterns.1213In this curated form, the skill is optimized for **analysis and review** of Node.js codebases, services, workers, CLIs, and internal tooling. It is especially useful when you need to assess:1415- runtime and release-line fit16- event-loop safety and async correctness17- framework necessity versus built-in platform features18- dependency and supply-chain discipline19- testing, diagnostics, and observability maturity20- security posture and operational readiness2122This is a **decision-making skill**, not a code-generation template. Use it to produce a justified review, recommendation, or architecture direction.2324## When to Use2526Use this skill when:2728- a team asks whether a Node.js service is production-ready29- you need to review architecture, framework choice, or async patterns30- a repository shows latency spikes, blocking work, or unstable concurrency behavior31- you need to judge whether built-in Node features can replace unnecessary dependencies32- you need a structured review of security, testing, diagnostics, or release hygiene33- the user wants best practices with rationale, trade-offs, and review criteria3435Do **not** use this skill as the primary workflow when:3637- the task is language-agnostic and not meaningfully Node-specific38- the user only wants implementation code with no review or architecture component39- the dominant problem is infrastructure-only and not connected to Node runtime behavior40- the codebase is browser-only JavaScript with no Node runtime concerns4142## Workflow43441. **Establish the review target**45 - Identify whether the subject is an API server, CLI, worker, monolith, library, or mixed repository.46 - Record the Node version policy from `.nvmrc`, `.node-version`, `package.json`, CI config, Dockerfile, or deployment manifests.47 - Confirm whether the question is about architecture, correctness, performance, security, or release readiness.48492. **Map runtime responsibilities**50 - Separate I/O-bound work from CPU-bound work.51 - Note where the process handles HTTP, queues, cron jobs, file I/O, streams, child processes, or crypto/compression.52 - Flag any work that appears likely to block the event loop.53543. **Review platform-fit decisions**55 - Check whether the codebase uses built-in capabilities appropriately before adding dependencies.56 - Look for valid use of modern Node facilities such as `node:test`, `AsyncLocalStorage`, `diagnostics_channel`, built-in `fetch`, `--env-file`, and permissions where relevant.57 - Challenge framework or library choices that add abstraction without solving a concrete problem.58594. **Assess correctness and maintainability**60 - Review async boundaries, error propagation, cancellation, shutdown behavior, and timeouts.61 - Check whether configuration is explicit, validated, and environment-specific.62 - Verify that modules, services, and adapters are separated cleanly enough to test and replace.63645. **Assess dependency and supply-chain discipline**65 - Review lockfile presence, install reproducibility, dependency sprawl, and package freshness.66 - Prefer `npm ci`-style reproducible installs in CI over drift-prone install flows.67 - Check whether dependency risk is controlled with minimal package count, provenance-aware publishing or consumption where applicable, and actionable audit handling rather than blind upgrades.68696. **Assess testing and diagnostics**70 - Check whether tests cover behavior at the right level: unit, integration, contract, and failure-path tests.71 - Look for observability support: structured logs, request or job correlation, health signals, metrics hooks, and useful crash diagnostics.72 - Review whether production debugging relies on stable mechanisms instead of ad hoc `console.log` sprawl.73747. **Assess operational safety**75 - Review input validation, secret handling, permissions, file-system scope, subprocess usage, and network exposure.76 - Confirm graceful shutdown, backpressure handling, and retry logic do not create duplicate work or data corruption.77 - Check whether defaults are safe under failure, not only under happy-path traffic.78798. **Produce a decision-oriented output**80 - Summarize findings as **keep**, **change**, or **investigate**.81 - Prioritize by impact: correctness and security first, then operability, then maintainability.82 - Recommend the smallest safe change that materially improves the system.8384## Review Output Format8586Use this structure when presenting results:8788- **Context:** what the service does and what Node is responsible for89- **Strengths:** practices worth preserving90- **Critical risks:** issues that can cause outages, corruption, or security exposure91- **Important improvements:** changes that improve resilience or clarity92- **Optional refinements:** nice-to-have improvements with lower urgency93- **Decision summary:** whether the current approach is acceptable, conditionally acceptable, or should be changed9495## Examples9697### Example 1: Short review summary9899```text100Target: Express-based internal API on Node 22101Decision: Conditionally acceptable102103Strengths:104- Uses LTS runtime in CI and production105- Has a lockfile and reproducible CI install106- Uses structured logging and graceful shutdown hooks107108Critical risks:109- Image processing runs inline on request path and blocks the event loop110- Request timeouts are missing on outbound fetch calls111- Input validation is inconsistent across routes112113Important improvements:114- Move CPU-heavy image work to a worker or separate service115- Wrap outbound I/O with explicit timeout and retry policy116- Centralize schema validation at the edge117```118119### Example 2: Framework challenge120121```text122Question: Should this small JSON API keep a large framework stack?123124Observed facts:125- 12 routes, minimal middleware, no SSR, no plugin ecosystem dependency126- Most code is validation, auth checks, and data access127- Team cites convenience, not a hard technical requirement128129Reasoned recommendation:130- Re-evaluate framework weight versus built-in HTTP support or a lighter server layer131- Keep the current framework only if it provides proven operational value such as standardized plugins, hooks, or team-wide conventions132- Do not rewrite purely for fashion; rewrite only if complexity reduction is measurable133```134135For deeper worked examples, open:136137- `examples/review-example.md`138- `examples/decision-scenarios.md`139140## Best Practices141142### Do143144- Prefer current supported Node release lines and document the target runtime explicitly.145- Distinguish CPU-bound work from I/O-bound work before discussing performance.146- Use built-in platform features when they meet the requirement cleanly.147- Require explicit timeouts, cancellation strategy, and error handling for outbound I/O.148- Keep request handlers thin; move business rules into testable modules.149- Preserve correlation context across async boundaries when tracing request or job flow matters.150- Use reproducible installs and review dependency additions as architecture decisions, not convenience-only changes.151- Treat observability as part of correctness: if failures cannot be diagnosed, the system is not truly production-ready.152153### Do Not154155- Recommend a framework because it is popular without tying it to delivery or operational benefit.156- Assume async code is safe just because it uses `await`.157- Put compression, crypto, large JSON transforms, image manipulation, or heavy parsing directly on hot request paths without justification.158- Accept unbounded concurrency, unbounded queues, or unbounded payload handling.159- Add packages for features already provided adequately by Node unless the package clearly reduces risk or complexity.160- Treat `npm audit` output as a mechanical upgrade queue; evaluate exploitability, reachability, and breakage risk.161- Rely on scattered environment variables with no validation or startup checks.162163## Troubleshooting164165**Symptoms:** Latency spikes under moderate traffic, CPU rises sharply, and unrelated requests slow down.166167**Solution:** Review for event-loop blocking work such as sync filesystem calls, large JSON parsing/stringifying, crypto/compression on the request path, regex backtracking, or CPU-heavy transforms. Move CPU-bound work to workers, queues, or another service boundary where justified.168169**Symptoms:** The service appears "async" but still hangs or times out unpredictably.170171**Solution:** Inspect outbound I/O for missing timeouts, retries without bounds, unresolved promises, and connection-pool exhaustion. Verify that every network call has explicit timeout behavior and failure handling.172173**Symptoms:** Logs are present, but incidents are still hard to trace across requests or jobs.174175**Solution:** Check whether correlation IDs or async context propagation are preserved consistently. Prefer structured logs and stable context propagation over ad hoc string logging.176177**Symptoms:** CI passes, but production fails after dependency updates or environment changes.178179**Solution:** Check for non-reproducible installs, weak lockfile discipline, runtime version drift, and configuration assumptions hidden in shell environments. Confirm that CI and production use the same Node major line and installation strategy.180181**Symptoms:** Memory growth appears gradual and hard to reproduce.182183**Solution:** Review long-lived caches, event listeners, stream lifecycle handling, and request-scoped state retained beyond completion. Check whether backpressure is ignored or whether large objects remain referenced in closures.184185For a faster diagnosis matrix, open `references/troubleshooting-matrix.md`.186187## Additional Resources188189- `references/review-criteria.md` — Open this when you need a compact but concrete Node.js review checklist with decision criteria.190- `references/troubleshooting-matrix.md` — Open this when symptoms are operational and you need likely causes plus targeted review checks.191- `examples/review-example.md` — Open this when you need a worked example of a review with findings and prioritization.192- `examples/decision-scenarios.md` — Open this when the user is asking "should we use X?" and you need scenario-based decisions.193194## Scope Notes195196This skill favors **judgment and review quality** over style debates. The best output is usually not "rewrite everything," but "keep what is working, change the parts that create measurable risk, and justify each recommendation in Node-specific terms."