{"id":"fecf8084-2f21-4f54-90e0-20d0d942bbb9","shortId":"J9hPfM","kind":"skill","title":"nodejs-best-practices","tagline":"Node.js development principles and decision-making. Framework selection, async patterns, security, and architecture. Teaches thinking, not copying.","description":"# Node.js Best Practices\n\n> Principles and decision-making for Node.js development in 2025.\n> **Learn to THINK, not memorize code patterns.**\n\n## When to Use\nUse this skill when making Node.js architecture decisions, choosing frameworks, designing async patterns, or applying security and deployment best practices.\n\n---\n\n## ⚠️ How to Use This Skill\n\nThis skill teaches **decision-making principles**, not fixed code to copy.\n\n- ASK user for preferences when unclear\n- Choose framework/pattern based on CONTEXT\n- Don't default to same solution every time\n\n---\n\n## 1. Framework Selection (2025)\n\n### Decision Tree\n\n```\nWhat are you building?\n│\n├── Edge/Serverless (Cloudflare, Vercel)\n│   └── Hono (zero-dependency, ultra-fast cold starts)\n│\n├── High Performance API\n│   └── Fastify (2-3x faster than Express)\n│\n├── Enterprise/Team familiarity\n│   └── NestJS (structured, DI, decorators)\n│\n├── Legacy/Stable/Maximum ecosystem\n│   └── Express (mature, most middleware)\n│\n└── Full-stack with frontend\n    └── Next.js API Routes or tRPC\n```\n\n### Comparison Principles\n\n| Factor | Hono | Fastify | Express |\n|--------|------|---------|---------|\n| **Best for** | Edge, serverless | Performance | Legacy, learning |\n| **Cold start** | Fastest | Fast | Moderate |\n| **Ecosystem** | Growing | Good | Largest |\n| **TypeScript** | Native | Excellent | Good |\n| **Learning curve** | Low | Medium | Low |\n\n### Selection Questions to Ask:\n1. What's the deployment target?\n2. Is cold start time critical?\n3. Does team have existing experience?\n4. Is there legacy code to maintain?\n\n---\n\n## 2. Runtime Considerations (2025)\n\n### Native TypeScript\n\n```\nNode.js 22+: --experimental-strip-types\n├── Run .ts files directly\n├── No build step needed for simple projects\n└── Consider for: scripts, simple APIs\n```\n\n### Module System Decision\n\n```\nESM (import/export)\n├── Modern standard\n├── Better tree-shaking\n├── Async module loading\n└── Use for: new projects\n\nCommonJS (require)\n├── Legacy compatibility\n├── More npm packages support\n└── Use for: existing codebases, some edge cases\n```\n\n### Runtime Selection\n\n| Runtime | Best For |\n|---------|----------|\n| **Node.js** | General purpose, largest ecosystem |\n| **Bun** | Performance, built-in bundler |\n| **Deno** | Security-first, built-in TypeScript |\n\n---\n\n## 3. Architecture Principles\n\n### Layered Structure Concept\n\n```\nRequest Flow:\n│\n├── Controller/Route Layer\n│   ├── Handles HTTP specifics\n│   ├── Input validation at boundary\n│   └── Calls service layer\n│\n├── Service Layer\n│   ├── Business logic\n│   ├── Framework-agnostic\n│   └── Calls repository layer\n│\n└── Repository Layer\n    ├── Data access only\n    ├── Database queries\n    └── ORM interactions\n```\n\n### Why This Matters:\n- **Testability**: Mock layers independently\n- **Flexibility**: Swap database without touching business logic\n- **Clarity**: Each layer has single responsibility\n\n### When to Simplify:\n- Small scripts → Single file OK\n- Prototypes → Less structure acceptable\n- Always ask: \"Will this grow?\"\n\n---\n\n## 4. Error Handling Principles\n\n### Centralized Error Handling\n\n```\nPattern:\n├── Create custom error classes\n├── Throw from any layer\n├── Catch at top level (middleware)\n└── Format consistent response\n```\n\n### Error Response Philosophy\n\n```\nClient gets:\n├── Appropriate HTTP status\n├── Error code for programmatic handling\n├── User-friendly message\n└── NO internal details (security!)\n\nLogs get:\n├── Full stack trace\n├── Request context\n├── User ID (if applicable)\n└── Timestamp\n```\n\n### Status Code Selection\n\n| Situation | Status | When |\n|-----------|--------|------|\n| Bad input | 400 | Client sent invalid data |\n| No auth | 401 | Missing or invalid credentials |\n| No permission | 403 | Valid auth, but not allowed |\n| Not found | 404 | Resource doesn't exist |\n| Conflict | 409 | Duplicate or state conflict |\n| Validation | 422 | Schema valid but business rules fail |\n| Server error | 500 | Our fault, log everything |\n\n---\n\n## 5. Async Patterns Principles\n\n### When to Use Each\n\n| Pattern | Use When |\n|---------|----------|\n| `async/await` | Sequential async operations |\n| `Promise.all` | Parallel independent operations |\n| `Promise.allSettled` | Parallel where some can fail |\n| `Promise.race` | Timeout or first response wins |\n\n### Event Loop Awareness\n\n```\nI/O-bound (async helps):\n├── Database queries\n├── HTTP requests\n├── File system\n└── Network operations\n\nCPU-bound (async doesn't help):\n├── Crypto operations\n├── Image processing\n├── Complex calculations\n└── → Use worker threads or offload\n```\n\n### Avoiding Event Loop Blocking\n\n- Never use sync methods in production (fs.readFileSync, etc.)\n- Offload CPU-intensive work\n- Use streaming for large data\n\n---\n\n## 6. Validation Principles\n\n### Validate at Boundaries\n\n```\nWhere to validate:\n├── API entry point (request body/params)\n├── Before database operations\n├── External data (API responses, file uploads)\n└── Environment variables (startup)\n```\n\n### Validation Library Selection\n\n| Library | Best For |\n|---------|----------|\n| **Zod** | TypeScript first, inference |\n| **Valibot** | Smaller bundle (tree-shakeable) |\n| **ArkType** | Performance critical |\n| **Yup** | Existing React Form usage |\n\n### Validation Philosophy\n\n- Fail fast: Validate early\n- Be specific: Clear error messages\n- Don't trust: Even \"internal\" data\n\n---\n\n## 7. Security Principles\n\n### Security Checklist (Not Code)\n\n- [ ] **Input validation**: All inputs validated\n- [ ] **Parameterized queries**: No string concatenation for SQL\n- [ ] **Password hashing**: bcrypt or argon2\n- [ ] **JWT verification**: Always verify signature and expiry\n- [ ] **Rate limiting**: Protect from abuse\n- [ ] **Security headers**: Helmet.js or equivalent\n- [ ] **HTTPS**: Everywhere in production\n- [ ] **CORS**: Properly configured\n- [ ] **Secrets**: Environment variables only\n- [ ] **Dependencies**: Regularly audited\n\n### Security Mindset\n\n```\nTrust nothing:\n├── Query params → validate\n├── Request body → validate\n├── Headers → verify\n├── Cookies → validate\n├── File uploads → scan\n└── External APIs → validate response\n```\n\n---\n\n## 8. Testing Principles\n\n### Test Strategy Selection\n\n| Type | Purpose | Tools |\n|------|---------|-------|\n| **Unit** | Business logic | node:test, Vitest |\n| **Integration** | API endpoints | Supertest |\n| **E2E** | Full flows | Playwright |\n\n### What to Test (Priorities)\n\n1. **Critical paths**: Auth, payments, core business\n2. **Edge cases**: Empty inputs, boundaries\n3. **Error handling**: What happens when things fail?\n4. **Not worth testing**: Framework code, trivial getters\n\n### Built-in Test Runner (Node.js 22+)\n\n```\nnode --test src/**/*.test.ts\n├── No external dependency\n├── Good coverage reporting\n└── Watch mode available\n```\n\n---\n\n## 10. Anti-Patterns to Avoid\n\n### ❌ DON'T:\n- Use Express for new edge projects (use Hono)\n- Use sync methods in production code\n- Put business logic in controllers\n- Skip input validation\n- Hardcode secrets\n- Trust external data without validation\n- Block event loop with CPU work\n\n### ✅ DO:\n- Choose framework based on context\n- Ask user for preferences when unclear\n- Use layered architecture for growing projects\n- Validate all inputs\n- Use environment variables for secrets\n- Profile before optimizing\n\n---\n\n## 11. Decision Checklist\n\nBefore implementing:\n\n- [ ] **Asked user about stack preference?**\n- [ ] **Chosen framework for THIS context?** (not just default)\n- [ ] **Considered deployment target?**\n- [ ] **Planned error handling strategy?**\n- [ ] **Identified validation points?**\n- [ ] **Considered security requirements?**\n\n---\n\n> **Remember**: Node.js best practices are about decision-making, not memorizing patterns. Every project deserves fresh consideration based on its requirements.\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.","tags":["nodejs","best","practices","antigravity","awesome","skills","sickn33","agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding"],"capabilities":["skill","source-sickn33","skill-nodejs-best-practices","topic-agent-skills","topic-agentic-skills","topic-ai-agent-skills","topic-ai-agents","topic-ai-coding","topic-ai-workflows","topic-antigravity","topic-antigravity-skills","topic-claude-code","topic-claude-code-skills","topic-codex-cli","topic-codex-skills"],"categories":["antigravity-awesome-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/sickn33/antigravity-awesome-skills/nodejs-best-practices","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add sickn33/antigravity-awesome-skills","source_repo":"https://github.com/sickn33/antigravity-awesome-skills","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 35034 github stars · SKILL.md body (8,063 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-25T12:51:06.461Z","embedding":null,"createdAt":"2026-04-18T20:25:31.181Z","updatedAt":"2026-04-25T12:51:06.461Z","lastSeenAt":"2026-04-25T12:51:06.461Z","tsv":"'-3':129 '1':102,191,745 '10':794 '11':866 '2':128,197,216,752 '2025':35,105,219 '22':223,780 '3':203,301,758 '4':209,377,766 '400':442 '401':449 '403':456 '404':464 '409':470 '422':476 '5':490 '500':485 '6':575 '7':642 '8':718 'abus':677 'accept':371 'access':334 'agnost':327 'allow':461 'alway':372,668 'anti':796 'anti-pattern':795 'api':126,152,243,584,594,715,734 'appli':60 'applic':432 'appropri':406 'architectur':18,52,302,851 'argon2':665 'arktyp':617 'ask':83,190,373,843,871,951 'async':14,57,255,491,503,525,538 'async/await':501 'audit':696 'auth':448,458,748 'avail':793 'avoid':553,799 'awar':523 'bad':440 'base':91,840,914 'bcrypt':663 'best':3,24,64,162,280,605,899 'better':251 'block':556,831 'bodi':705 'body/params':588 'bound':537 'boundari':317,580,757,959 'build':111,233 'built':290,298,775 'built-in':289,297,774 'bun':287 'bundl':613 'bundler':292 'busi':323,352,480,728,751,817 'calcul':547 'call':318,328 'case':276,754 'catch':393 'central':381 'checklist':646,868 'choos':54,89,838 'chosen':876 'clarif':953 'clariti':354 'class':388 'clear':633,926 'client':404,443 'cloudflar':113 'code':41,80,213,410,435,648,771,815 'codebas':273 'cold':122,169,199 'commonj':262 'comparison':156 'compat':265 'complex':546 'concaten':658 'concept':306 'configur':689 'conflict':469,474 'consid':239,884,894 'consider':218,913 'consist':399 'context':93,428,842,880 'control':820 'controller/route':309 'cooki':709 'copi':22,82 'cor':687 'core':750 'coverag':789 'cpu':536,567,835 'cpu-bound':535 'cpu-intens':566 'creat':385 'credenti':453 'criteria':962 'critic':202,619,746 'crypto':542 'curv':183 'custom':386 'data':333,446,574,593,641,828 'databas':336,349,527,590 'decis':10,29,53,75,106,246,867,904 'decision-mak':9,28,74,903 'decor':139 'default':96,883 'deno':293 'depend':118,694,787 'deploy':63,195,885 'describ':930 'deserv':911 'design':56 'detail':420 'develop':6,33 'di':138 'direct':231 'doesn':466,539 'duplic':471 'e2e':737 'earli':630 'ecosystem':141,174,286 'edg':164,275,753,806 'edge/serverless':112 'empti':755 'endpoint':735 'enterprise/team':134 'entri':585 'environ':598,691,859,942 'environment-specif':941 'equival':682 'error':378,382,387,401,409,484,634,759,888 'esm':247 'etc':564 'even':639 'event':521,554,832 'everi':100,909 'everyth':489 'everywher':684 'excel':180 'exist':207,272,468,621 'experi':208 'experiment':225 'experimental-strip-typ':224 'expert':947 'expiri':672 'express':133,142,161,803 'extern':592,714,786,827 'factor':158 'fail':482,514,627,765 'familiar':135 'fast':121,172,628 'faster':131 'fastest':171 'fastifi':127,160 'fault':487 'file':230,366,531,596,711 'first':296,518,609 'fix':79 'flexibl':347 'flow':308,739 'form':623 'format':398 'found':463 'framework':12,55,103,326,770,839,877 'framework-agnost':325 'framework/pattern':90 'fresh':912 'friend':416 'frontend':150 'fs.readfilesync':563 'full':147,424,738 'full-stack':146 'general':283 'get':405,423 'getter':773 'good':176,181,788 'grow':175,376,853 'handl':311,379,383,413,760,889 'happen':762 'hardcod':824 'hash':662 'header':679,707 'helmet.js':680 'help':526,541 'high':124 'hono':115,159,809 'http':312,407,529 'https':683 'i/o-bound':524 'id':430 'identifi':891 'imag':544 'implement':870 'import/export':248 'independ':346,507 'infer':610 'input':314,441,649,652,756,822,857,956 'integr':733 'intens':568 'interact':339 'intern':419,640 'invalid':445,452 'jwt':666 'larg':573 'largest':177,285 'layer':304,310,320,322,330,332,345,356,392,850 'learn':36,168,182 'legaci':167,212,264 'legacy/stable/maximum':140 'less':369 'level':396 'librari':602,604 'limit':674,918 'load':257 'log':422,488 'logic':324,353,729,818 'loop':522,555,833 'low':184,186 'maintain':215 'make':11,30,50,76,905 'match':927 'matter':342 'matur':143 'medium':185 'memor':40,907 'messag':417,635 'method':560,812 'middlewar':145,397 'mindset':698 'miss':450,964 'mock':344 'mode':792 'moder':173 'modern':249 'modul':244,256 'nativ':179,220 'need':235 'nestj':136 'network':533 'never':557 'new':260,805 'next.js':151 'node':730,781 'node.js':5,23,32,51,222,282,779,898 'nodej':2 'nodejs-best-practic':1 'noth':700 'npm':267 'offload':552,565 'ok':367 'oper':504,508,534,543,591 'optim':865 'orm':338 'output':936 'packag':268 'parallel':506,510 'param':702 'parameter':654 'password':661 'path':747 'pattern':15,42,58,384,492,498,797,908 'payment':749 'perform':125,166,288,618 'permiss':455,957 'philosophi':403,626 'plan':887 'playwright':740 'point':586,893 'practic':4,25,65,900 'prefer':86,846,875 'principl':7,26,77,157,303,380,493,577,644,720 'prioriti':744 'process':545 'product':562,686,814 'profil':863 'programmat':412 'project':238,261,807,854,910 'promise.all':505 'promise.allsettled':509 'promise.race':515 'proper':688 'protect':675 'prototyp':368 'purpos':284,725 'put':816 'queri':337,528,655,701 'question':188 'rate':673 'react':622 'regular':695 'rememb':897 'report':790 'repositori':329,331 'request':307,427,530,587,704 'requir':263,896,917,955 'resourc':465 'respons':359,400,402,519,595,717 'review':948 'rout':153 'rule':481 'run':228 'runner':778 'runtim':217,277,279 'safeti':958 'scan':713 'schema':477 'scope':929 'script':241,364 'secret':690,825,862 'secur':16,61,295,421,643,645,678,697,895 'security-first':294 'select':13,104,187,278,436,603,723 'sent':444 'sequenti':502 'server':483 'serverless':165 'servic':319,321 'shake':254 'shakeabl':616 'signatur':670 'simpl':237,242 'simplifi':362 'singl':358,365 'situat':437 'skill':48,70,72,921 'skill-nodejs-best-practices' 'skip':821 'small':363 'smaller':612 'solut':99 'source-sickn33' 'specif':313,632,943 'sql':660 'src':783 'stack':148,425,874 'standard':250 'start':123,170,200 'startup':600 'state':473 'status':408,434,438 'step':234 'stop':949 'strategi':722,890 'stream':571 'string':657 'strip':226 'structur':137,305,370 'substitut':939 'success':961 'supertest':736 'support':269 'swap':348 'sync':559,811 'system':245,532 'target':196,886 'task':925 'teach':19,73 'team':205 'test':719,721,731,743,769,777,782,945 'test.ts':784 'testabl':343 'thing':764 'think':20,38 'thread':550 'throw':389 'time':101,201 'timeout':516 'timestamp':433 'tool':726 'top':395 'topic-agent-skills' 'topic-agentic-skills' 'topic-ai-agent-skills' 'topic-ai-agents' 'topic-ai-coding' 'topic-ai-workflows' 'topic-antigravity' 'topic-antigravity-skills' 'topic-claude-code' 'topic-claude-code-skills' 'topic-codex-cli' 'topic-codex-skills' 'touch':351 'trace':426 'treat':934 'tree':107,253,615 'tree-shak':252,614 'trivial':772 'trpc':155 'trust':638,699,826 'ts':229 'type':227,724 'typescript':178,221,300,608 'ultra':120 'ultra-fast':119 'unclear':88,848 'unit':727 'upload':597,712 'usag':624 'use':45,46,68,258,270,496,499,548,558,570,802,808,810,849,858,919 'user':84,415,429,844,872 'user-friend':414 'valibot':611 'valid':315,457,475,478,576,578,583,601,625,629,650,653,703,706,710,716,823,830,855,892,944 'variabl':599,692,860 'vercel':114 'verif':667 'verifi':669,708 'vitest':732 'watch':791 'win':520 'without':350,829 'work':569,836 'worker':549 'worth':768 'x':130 'yup':620 'zero':117 'zero-depend':116 'zod':607","prices":[{"id":"d6acbd18-4dfa-482f-a01d-b39aa4c2866c","listingId":"fecf8084-2f21-4f54-90e0-20d0d942bbb9","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"sickn33","category":"antigravity-awesome-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T20:25:31.181Z"}],"sources":[{"listingId":"fecf8084-2f21-4f54-90e0-20d0d942bbb9","source":"github","sourceId":"sickn33/antigravity-awesome-skills/nodejs-best-practices","sourceUrl":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/nodejs-best-practices","isPrimary":false,"firstSeenAt":"2026-04-18T21:41:27.122Z","lastSeenAt":"2026-04-25T12:51:06.461Z"},{"listingId":"fecf8084-2f21-4f54-90e0-20d0d942bbb9","source":"skills_sh","sourceId":"sickn33/antigravity-awesome-skills/nodejs-best-practices","sourceUrl":"https://skills.sh/sickn33/antigravity-awesome-skills/nodejs-best-practices","isPrimary":true,"firstSeenAt":"2026-04-18T20:25:31.181Z","lastSeenAt":"2026-04-25T12:40:09.709Z"}],"details":{"listingId":"fecf8084-2f21-4f54-90e0-20d0d942bbb9","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"sickn33","slug":"nodejs-best-practices","github":{"repo":"sickn33/antigravity-awesome-skills","stars":35034,"topics":["agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows","antigravity","antigravity-skills","claude-code","claude-code-skills","codex-cli","codex-skills","cursor","cursor-skills","developer-tools","gemini-cli","gemini-skills","kiro","mcp","skill-library"],"license":"mit","html_url":"https://github.com/sickn33/antigravity-awesome-skills","pushed_at":"2026-04-25T06:33:17Z","description":"Installable GitHub library of 1,400+ agentic skills for Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and more. Includes installer CLI, bundles, workflows, and official/community skill collections.","skill_md_sha":"1a9cb2070c9ff6e593f2d5d9cded2ad1185b51df","skill_md_path":"skills/nodejs-best-practices/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/nodejs-best-practices"},"layout":"multi","source":"github","category":"antigravity-awesome-skills","frontmatter":{"name":"nodejs-best-practices","description":"Node.js development principles and decision-making. Framework selection, async patterns, security, and architecture. Teaches thinking, not copying."},"skills_sh_url":"https://skills.sh/sickn33/antigravity-awesome-skills/nodejs-best-practices"},"updatedAt":"2026-04-25T12:51:06.461Z"}}