nodejs-best-practices
Expert guidance on modern Node.js architectural decisions.
Install
mkdir -p .claude/skills/nodejs-best-practices-harmitx7 && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/15635" && unzip -o skill.zip -d .claude/skills/nodejs-best-practices-harmitx7 && rm skill.zipInstalls to .claude/skills/nodejs-best-practices-harmitx7
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Node.js development principles and decision-making. Framework selection, async patterns, security, and architecture. Teaches thinking, not copying.Key capabilities
- →Select appropriate Node.js frameworks based on project context
- →Understand the modern JavaScript runtime landscape including Node.js, Bun, and Deno
- →Implement reliable asynchronous patterns, including handling rejections and avoiding event loop blocking
- →Design structured error handling architectures with custom error classes
- →Apply security baselines using middleware like Helmet and rate limiting
- →Organize project structure with clear separation of concerns
How it works
The skill provides principles and examples for Node.js development, covering framework selection, async patterns, security, and architecture. It emphasizes understanding underlying mechanisms rather than rote copying.
Inputs & outputs
When to use nodejs-best-practices
- →Selecting node frameworks
- →Architecting async applications
- →Choosing between Node and Bun
- →Improving runtime security
About this skill
Node.js Development Principles
Node.js is not a problem — unpredictable async behavior is. Understand the event loop and half of Node.js "gotchas" disappear.
Framework Selection
| Context | Recommended | Why |
|---|---|---|
| REST API, standard patterns | Express + TypeScript | Mature, flexible, most hiring knowledge |
| REST API, speed + TypeScript-first | Fastify | 2x Express throughput, built-in validation |
| Full-stack React | Next.js API routes | Colocated API and UI, serverless-friendly |
| REST + tRPC | Next.js + tRPC | Type-safe end-to-end with no code generation |
| RPC across services | gRPC | Binary protocol, contract-first |
| Edge function / Cloudflare Worker | Hono | Tiny, Web Platform API-native, zero cold start |
| Scripts / tooling / bun-native | Bun | Built-in bundler, test runner, near-Node compat |
Questions to ask before choosing:
- Is this public-facing or internal?
- Do we control the deployment environment (server vs. serverless vs. edge)?
- Is the team already familiar with a framework?
- Does this need to compose with an existing TypeScript frontend?
Modern Runtime Landscape (2025+)
The Node.js monopoly is ending. Understand constraints before picking a runtime:
| Runtime | fs | crypto | child_process | process.env | Deploy Target |
|---|---|---|---|---|---|
| Node.js | ✅ | ✅ | ✅ | ✅ | Server, serverless |
| Bun | ✅ | ✅ | ✅ | ✅ | Server (Node-compatible) |
| Deno | ✅ (explicit perm) | ✅ | ✅ (explicit perm) | ✅ | Server, Deno Deploy |
| Edge (Cloudflare Workers) | ❌ | Web only | ❌ | via env binding | Edge (global) |
// ❌ Portability anti-pattern — works in Node, breaks at edge
import { createHash } from 'crypto'; // Node crypto — not available at edge
import fs from 'fs'; // No filesystem at edge
// ✅ Web Platform APIs — work everywhere (Node ≥18, Bun, Deno, Edge)
const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(input));
const response = await fetch('https://api.example.com/data');
When to Consider Bun
// Bun is Node-compatible but: starts faster, ships a bundler + test runner built-in
// Use Bun when: scripts, tooling, new greenfield backends, or test-heavy projects
// package.json — identical, works in both
// bun install → 10x faster than npm install
// bun test → built-in Vitest-compatible runner
// bun run → direct TypeScript execution, no transpile step
// Gotcha: some native Node addons (e.g. bcrypt, canvas) need Bun alternatives
// Use: @node-rs/bcrypt instead of bcrypt (N-API native, works in both)
Async Patterns
Always: Handle rejection
Every Promise needs a rejection handler. Unhandled rejections crash Node.js processes in modern versions.
// ❌ Unhandled rejection
fetchData().then(process);
// ✅ Handled
fetchData().then(process).catch(handleError);
// ✅ Or with async/await
try {
const data = await fetchData();
process(data);
} catch (err) {
handleError(err);
}
Avoid: Blocking the event loop
The event loop is single-threaded. Anything synchronous that takes more than a few ms blocks all other requests.
// ❌ Blocks event loop for large files
const data = fs.readFileSync('huge.csv');
// ✅ Non-blocking
const data = await fs.promises.readFile('huge.csv');
// ❌ CPU-intensive work on main thread
const result = computeHuge(dataset);
// ✅ Offload to worker thread
const { Worker } = require('worker_threads');
Concurrency vs. Parallelism
// Sequential — each awaits the previous (use when order matters or requests are dependent)
for (const id of ids) {
await processItem(id);
}
// Concurrent — all start immediately, await all completions (use for independent operations)
await Promise.all(ids.map(id => processItem(id)));
// Concurrent with limit — avoid overwhelming downstream services
import pLimit from 'p-limit';
const limit = pLimit(5); // max 5 concurrent
await Promise.all(ids.map(id => limit(() => processItem(id))));
Error Handling Architecture
Structure errors so they carry meaning, not just messages:
// Base application error
class AppError extends Error {
constructor(
message: string,
public code: string,
public statusCode: number,
public isOperational = true
) {
super(message);
this.name = this.constructor.name;
}
}
// Domain-specific errors
class NotFoundError extends AppError {
constructor(resource: string, id: string) {
super(`${resource} ${id} not found`, 'NOT_FOUND', 404);
}
}
class ValidationError extends AppError {
constructor(message: string) {
super(message, 'VALIDATION_FAILED', 400);
}
}
Global error handler:
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
if (err instanceof AppError && err.isOperational) {
return res.status(err.statusCode).json({
error: err.message,
code: err.code,
});
}
// Non-operational errors — log fully, don't expose details
logger.error('Unexpected error', { err, url: req.url });
res.status(500).json({ error: 'Internal server error' });
});
Security Baseline
import helmet from 'helmet';
import rateLimit from 'express-rate-limit';
// Security headers
app.use(helmet());
// Rate limiting — protect all routes
app.use(rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // requests per window
standardHeaders: true,
legacyHeaders: false,
}));
// Body size limit — prevent payload bombs
app.use(express.json({ limit: '10kb' }));
// Trust proxy correctly for rate limiting behind load balancer
app.set('trust proxy', 1);
Never:
- Use
eval()ornew Function()with user input - Pass unvalidated user input to
exec(),spawn(), orchild_process - Log full request bodies (may contain credentials or PII)
Project Structure
src/
routes/ HTTP route definitions (thin — only parse and delegate)
controllers/ Request handling, validation, response formatting
services/ Business logic (no HTTP awareness)
repositories/ Database access (no business logic)
middleware/ Auth, rate limit, logging
lib/ Shared utilities (date, crypto, validation)
types/ TypeScript interfaces and type exports
config/ Environment config with validation
Dependency direction: routes → controllers → services → repositories Never: repositories calling services, or services knowing about HTTP
Output Format
When this skill produces or reviews code, structure your output as follows:
━━━ Nodejs Best Practices Report ━━━━━━━━━━━━━━━━━━━━━━━━
Skill: Nodejs Best Practices
Language: [detected language / framework]
Scope: [N files · N functions]
─────────────────────────────────────────────────
✅ Passed: [checks that passed, or "All clean"]
⚠️ Warnings: [non-blocking issues, or "None"]
❌ Blocked: [blocking issues requiring fix, or "None"]
─────────────────────────────────────────────────
VBC status: PENDING → VERIFIED
Evidence: [test output / lint pass / compile success]
VBC (Verification-Before-Completion) is mandatory. Do not mark status as VERIFIED until concrete terminal evidence is provided.
🏛️ Tribunal Integration (Anti-Hallucination)
Slash command: /tribunal-backend
Active reviewers: logic · security · dependency · type-safety
❌ Forbidden AI Tropes in Node.js
- Blindly mixing
requireandimport— pick ESM or CommonJS and stick to it strictly based onpackage.json. - "Catch-all and ignore" error handling — e.g.,
catch (e) { console.log(e); }without throwing or returning an error response. - Assuming Express — if the project is Next.js, Fastify, or NestJS, do not hallucinate Express code.
- Unparameterized queries — never interpolate strings into SQL.
- No
anytypes — unless an external library leaves no choice, type all request bodies and responses.
✅ Pre-Flight Self-Audit
Review these questions before generating Node.js code:
✅ Did I use the correct module system (CJS vs ESM) for this context?
✅ Is every Promise rejection properly handled?
✅ Did I block the event loop with synchronous FS or Crypto operations?
✅ Are all inputs validated before business logic runs?
✅ Is this code safe from memory leaks (e.g., unbounded arrays/maps)?
When not to use it
- →When the user needs to blindly mix `require` and `import` statements
- →When the user wants to use 'catch-all and ignore' error handling
- →When the user assumes Express for all projects
Limitations
- →Never output a prompt without first confirming the target tool.
- →Never embed techniques that cause fabrication in single-prompt execution.
- →Never ask more than 3 clarifying questions before producing a prompt.
How it compares
This skill offers structured guidance and decision-making frameworks for Node.js development, promoting thoughtful engineering choices over generic code generation.
Compared to similar skills
nodejs-best-practices side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| nodejs-best-practices (this skill) | 0 | 5mo | Review | Advanced |
| architecture-patterns | 55 | 2mo | No flags | Advanced |
| nodejs-best-practices | 28 | 6mo | No flags | Advanced |
| workflow-orchestration-patterns | 10 | 2mo | No flags | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by Harmitx7
View all by Harmitx7 →You might also like
architecture-patterns
wshobson
Implement proven backend architecture patterns including Clean Architecture, Hexagonal Architecture, and Domain-Driven Design. Use when architecting complex backend systems or refactoring existing applications for better maintainability.
nodejs-best-practices
davila7
Node.js development principles and decision-making. Framework selection, async patterns, security, and architecture. Teaches thinking, not copying.
workflow-orchestration-patterns
wshobson
Design durable workflows with Temporal for distributed systems. Covers workflow vs activity separation, saga patterns, state management, and determinism constraints. Use when building long-running processes, distributed transactions, or microservice orchestration.
nestjs-expert
davila7
Nest.js framework expert specializing in module architecture, dependency injection, middleware, guards, interceptors, testing with Jest/Supertest, TypeORM/Mongoose integration, and Passport.js authentication. Use PROACTIVELY for any Nest.js application issues including architecture decisions, testing strategies, performance optimization, or debugging complex dependency injection problems. If a specialized expert is a better fit, I will recommend switching and stop.
nodejs-backend-patterns
wshobson
Build production-ready Node.js backend services with Express/Fastify, implementing middleware patterns, error handling, authentication, database integration, and API design best practices. Use when creating Node.js servers, REST APIs, GraphQL backends, or microservices architectures.
backend-patterns
affaan-m
后端架构模式、API设计、数据库优化以及针对Node.js、Express和Next.js API路由的服务器端最佳实践。