nodejs-best-practices について
Node.js 開発者がプロジェクトに応じてフレームワーク、ランタイム、アーキテクチャを選び、検証・セキュリティ・テストを検討するための判断指針です。固定パターンの暗記ではなく、要件に応じた選択を重視します。
主な機能
- 01デプロイ環境に応じたフレームワーク選択
- 02ランタイムとモジュール方式の比較
- 03レイヤードアーキテクチャの原則
- 04エラー処理と非同期パターン
- 05検証とセキュリティのチェックリスト
- 06テスト戦略とアンチパターン
活用シーン
- 01新しい API のフレームワーク選定
- 02アーキテクチャとモジュール方式の計画
- 03入力検証とセキュリティ対策の確認
- 04重要な処理経路のテスト計画
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ davila7/ claude-code-templates --skill nodejs-best-practicesインストール後、Claude Code で/nodejs-best-practicesを入力して読み込まれたか確認します。
詳細
Node.js ベストプラクティス
2025年における Node.js 開発の原則と意思決定。 コードパターンを暗記するのではなく、考え方を学びましょう。
⚠️ このスキルの使い方
このスキルは、そのままコピーして使う固定のコードではなく、意思決定の原則を示すものです。
- 不明な場合は、ユーザーに好みを確認してください
- 状況(CONTEXT)に応じてフレームワークやパターンを選択してください
- 毎回同じ解決策をデフォルトにしないでください
1. フレームワークの選択(2025年)
決定木
What are you building?
│
├── Edge/Serverless (Cloudflare, Vercel)
│ └── Hono (zero-dependency, ultra-fast cold starts)
│
├── High Performance API
│ └── Fastify (2-3x faster than Express)
│
├── Enterprise/Team familiarity
│ └── NestJS (structured, DI, decorators)
│
├── Legacy/Stable/Maximum ecosystem
│ └── Express (mature, most middleware)
│
└── Full-stack with frontend
└── Next.js API Routes or tRPC
比較の原則
| 要素 | Hono | Fastify | Express |
|---|---|---|---|
| 最適な用途 | エッジ、サーバーレス | パフォーマンス | レガシー、学習 |
| コールドスタート | 最速 | 高速 | 中程度 |
| エコシステム | 成長中 | 良好 | 最大 |
| TypeScript | ネイティブ対応 | 優秀 | 良好 |
| 学習曲線 | 低い | 中程度 | 低い |
確認すべき選択の質問:
- デプロイ先はどこですか?
- コールドスタート時間は重要ですか?
- チームに既存の経験はありますか?
- 保守が必要なレガシーコードはありますか?
2. ランタイムに関する考慮事項(2025年)
ネイティブ TypeScript
Node.js 22+: --experimental-strip-types
├── Run .ts files directly
├── No build step needed for simple projects
└── Consider for: scripts, simple APIs
モジュールシステムの決定
ESM (import/export)
├── Modern standard
├── Better tree-shaking
├── Async module loading
└── Use for: new projects
CommonJS (require)
├── Legacy compatibility
├── More npm packages support
└── Use for: existing codebases, some edge cases
ランタイムの選択
| ランタイム | 最適な用途 |
|---|---|
| Node.js | 汎用、最大のエコシステム |
| Bun | パフォーマンス、組み込みバンドラー |
| Deno | セキュリティ重視、組み込み TypeScript |
3. アーキテクチャの原則
レイヤー構造の考え方
Request Flow:
│
├── Controller/Route Layer
│ ├── Handles HTTP specifics
│ ├── Input validation at boundary
│ └── Calls service layer
│
├── Service Layer
│ ├── Business logic
│ ├── Framework-agnostic
│ └── Calls repository layer
│
└── Repository Layer
├── Data access only
├── Database queries
└── ORM interactions
これが重要な理由:
- テスト容易性: 各レイヤーを独立してモック化できる
- 柔軟性: ビジネスロジックに触れずにデータベースを入れ替えられる
- 明確さ: 各レイヤーが単一の責務を持つ
簡略化すべきとき:
- 小規模なスクリプト → 単一ファイルで問題ありません
- プロトタイプ → 構造は少なめでも許容されます
- 常に問いかけてください: 「これは成長するだろうか?」
4. エラー処理の原則
集中型エラー処理
Pattern:
├── Create custom error classes
├── Throw from any layer
├── Catch at top level (middleware)
└── Format consistent response
エラーレスポンスの考え方
Client gets:
├── Appropriate HTTP status
├── Error code for programmatic handling
├── User-friendly message
└── NO internal details (security!)
Logs get:
├── Full stack trace
├── Request context
├── User ID (if applicable)
└── Timestamp
ステータスコードの選択
| 状況 | ステータス | 使用するタイミング |
|---|---|---|
| 不正な入力 | 400 | クライアントが無効なデータを送信した |
| 認証なし | 401 | 認証情報がない、または無効 |
| 権限なし | 403 | 認証は有効だが、許可されていない |
| 見つからない | 404 | リソースが存在しない |
| 競合 | 409 | 重複または状態の競合 |
| バリデーション | 422 | スキーマは有効だが、ビジネスルールに違反 |
| サーバーエラー | 500 | サーバー側の問題。すべてログに記録する |
5. 非同期パターンの原則
各パターンの使い分け
| パターン | 使用するタイミング |
|---|---|
async/await | 順次実行される非同期処理 |
Promise.all | 互いに独立した並列処理 |
Promise.allSettled | 一部が失敗する可能性のある並列処理 |
Promise.race | タイムアウト、または最初の応答を採用する場合 |
イベントループの理解
I/O-bound (async helps):
├── Database queries
├── HTTP requests
├── File system
└── Network operations
CPU-bound (async doesn't help):
├── Crypto operations
├── Image processing
├── Complex calculations
└── → Use worker threads or offload
イベントループのブロッキングを避ける
- 本番環境では同期メソッドを使用しない(fs.readFileSync など)
- CPU負荷の高い処理はオフロードする
- 大きなデータにはストリーミングを使用する
6. バリデーションの原則
境界でバリデーションを行う
Where to validate:
├── API entry point (request body/params)
├── Before database operations
├── External data (API responses, file uploads)
└── Environment variables (startup)
バリデーションライブラリの選択
| ライブラリ | 最適な用途 |
|---|---|
| Zod | TypeScript ファースト、型推論 |
| Valibot | バンドルサイズが小さい(ツリーシェイク可能) |
| ArkType | パフォーマンスが重要な場合 |
| Yup | 既存の React フォームでの利用 |
バリデーションの考え方
- 早期に失敗させる: できるだけ早くバリデーションする
- 具体的にする: 明確なエラーメッセージを返す
- 信頼しない: 「内部」のデータであっても検証する
7. セキュリティの原則
セキュリティチェックリスト(コードではなく項目)
- 入力のバリデーション: すべての入力を検証する
- パラメータ化クエリ: SQL に文字列連結を使用しない
- パスワードのハッシュ化: bcrypt または argon2
- JWT の検証: 署名と有効期限を必ず検証する
- レート制限: 不正利用から保護する
- セキュリティヘッダー: Helmet.js または同等のもの
- HTTPS: 本番環境ではすべてで使用する
- CORS: 適切に設定する
- シークレット: 環境変数のみを使用する
- 依存関係: 定期的に監査する
セキュリティの考え方
Trust nothing:
├── Query params → validate
├── Request body → validate
├── Headers → verify
├── Cookies → validate
├── File uploads → scan
└── External APIs → validate response
8. テストの原則
テスト戦略の選択
| 種類 | 目的 | ツール |
|---|---|---|
| ユニット | ビジネスロジック | node:test, Vitest |
| インテグレーション | API エンドポイント | Supertest |
| E2E | 一連のフロー全体 | Playwright |
テスト対象の優先順位
- 重要なパス: 認証、決済、コアのビジネスロジック
- エッジケース: 空の入力、境界値
- エラー処理: 処理が失敗したときに何が起こるか?
- テストする価値が低いもの: フレームワークのコード、単純なゲッター
組み込みテストランナー(Node.js 22+)
node --test src/**/*.test.ts
├── No external dependency
├── Good coverage reporting
└── Watch mode available
10. 避けるべきアンチパターン
❌ やってはいけないこと:
- 新しいエッジプロジェクトで Express を使う(Hono を使用してください)
- 本番コードで同期メソッドを使う
- ビジネスロジックをコントローラーに書く
- 入力バリデーションを省略する
- シークレットをハードコーディングする
- 検証せずに外部データを信頼する
- CPU 負荷の高い処理でイベントループをブロックする
✅ 推奨事項:
- コンテキストに基づいてフレームワークを選択する
- 不明な点があればユーザーに希望を確認する
- 成長中のプロジェクトではレイヤードアーキテクチャを使う
- すべての入力を検証する
- シークレットには環境変数を使う
- 最適化の前にプロファイリングを行う
11. 意思決定チェックリスト
実装前に確認してください:
- ユーザーにスタックの希望を確認したか?
- デフォルトではなく、この状況に合ったフレームワークを選んだか?
- デプロイ先を考慮したか?
- エラー処理の戦略を立てたか?
- バリデーションを行うポイントを特定したか?
- セキュリティ要件を考慮したか?
覚えておくこと: Node.js のベストプラクティスは、パターンを暗記することではなく、判断を行うことに関するものです。すべてのプロジェクトは、その要件に基づいて毎回改めて検討する価値があります。
コメント
Markdown 対応