Node.js
Node.jsとは
Node.jsは、ブラウザの外で [[JavaScript]] を実行するためのランタイム(実行環境)です。Chromeと同じV8エンジンを搭載し、Webサーバー・CLIツール・ビルドツールなど、あらゆるプログラムをJavaScriptで書けるようにします。
import http from 'node:http'
http.createServer((req, res) => {
res.end('Hello from Node.js')
}).listen(3000)
冒頭の node: は「npmで入れたパッケージではなくNode.js組み込みのモジュール」を示す書き方です。同名パッケージとの取り違えを防げます。
初学者向けポイント
- フロントエンドの開発ツール([[Vite]] など)も実はNode.js上で動いている。フロント開発者にも必須の基盤
- 非同期I/O が最大の特徴。ファイル読み書きや通信を「待たずに」次の処理へ進むため、大量の同時接続に強い
- パッケージ管理は npm。
package.jsonに依存関係を記録する
主な用途
| 用途 | 例 |
|---|---|
| APIサーバー | Express / Fastify / Hono で [[REST API]] を提供 |
| CLIツール | コード整形、ビルド、コード生成 |
| ビルド基盤 | [[Vite]]、各種バンドラー |
| リアルタイム通信 | WebSocketを使ったチャットなど |
1本のスレッドで動くということ
Node.jsはJavaScriptを1本のスレッドで実行します。同時に届いた100件のリクエストも、順番に少しずつ進みます。それでも大量の同時接続をさばけるのは、DBの応答やファイル読み書きといった待ち時間の間に、別のリクエストの続きへ切り替えるからです。この切り替えを回している仕組みがイベントループで、原理は [[並行処理と非同期]] にまとまっています。
裏を返すと、待ちではない処理でスレッドを占有すると全員が止まります。1リクエストあたり200ミリ秒かかる画像処理やパスワードのハッシュ計算をその場で実行すると、10件同時に来たときの最後の人は2秒待たされます。DBを1件引くだけの軽いAPIも、同じプロセスにいる限り巻き添えです。「特定の重いAPIを叩いた瞬間、無関係な画面まで固まる」という症状はこれが原因のことが多くあります。
対処は2方向です。重い計算は worker_threads で別スレッドへ逃がすか、キューに積んで別プロセスに任せます。またJavaScriptを実行するスレッドは1プロセスに1本なので、何もしなければCPUコアを1つ分しか使い切れません。本番ではコア数に合わせて同じアプリを複数プロセス立ち上げ、前段で振り分けるのが基本構成になります([[プロセスとスレッド]])。
モジュールの書き方が2つある
初学者が最初につまずくのがここです。Node.jsには歴史的に CommonJS(require / module.exports)があり、後から標準の ESモジュール(import / export)が加わりました。ファイルがどちらとして読まれるかで、書ける構文が変わります。
| 条件 | .js の扱い |
|---|---|
package.json に "type": "module" がある | ESモジュール |
| 記述が無い(既定) | CommonJS |
拡張子が .mjs / .cjs | 拡張子が形式を明示し、type より優先される |
出るエラーで見分けられます。Cannot use import statement outside a module はCommonJS扱いのファイルで import を書いたとき、require is not defined in ES module scope はその逆です。またESモジュールでは相対 import の拡張子を省略できず、./utils ではなく ./utils.js と書きます。バンドラ側から見た同じ話は [[ESモジュールとバンドラ]] にあります。
バージョンの選び方
Node.jsのメジャーバージョンは偶数番だけがLTS(長期サポート)になります。奇数番は新機能の実験場でサポート期間が短いため、業務では原則使いません。迷ったら「最新のLTS」で外しません。
- チームで版をそろえるには
.nvmrcにバージョンを書き、package.jsonのenginesにも動作範囲を書いておく - 版が上がると使える標準機能も増える。Node.js 18以降は
fetchが標準で使え、HTTP通信のためにライブラリを足す必要が減った([[fetchと非同期通信]]) - [[Docker]] のイメージタグや [[CI/CD]] の設定にも同じ版を書き、手元と本番をずらさない
Node.jsから次に読む地図
Node.jsは「JavaScriptを動かす土台」なので、隣接する記事は用途ごとに散らばります。今の目的に近い群から読むと迷いません。
言語と実行のしくみを知る
[[JavaScript]] と [[TypeScript]] が実際に書く言語、[[並行処理と非同期]] が「なぜ1スレッドで速いのか」の原理、[[ESモジュールとバンドラ]] が import / export の作法です。この3方向を押さえると、以降に出会うエラーメッセージの意味が読めるようになります。
サーバーとして動かす
Node.jsアプリは [[Webサーバーとアプリケーションサーバー]] でいうアプリケーションサーバーにあたり、前段にWebサーバーを置く理由はそちらにあります。公開するAPIの形は [[REST API]] か [[GraphQL]] を選ぶことになり、ExpressやFastifyといった土台の選び方は [[フレームワーク]] が扱います。
フロントエンド開発の基盤として使う
[[Vite]] をはじめとする開発ツールもNode.js上で動きます。パッケージの入手と版の固定は [[npmとパッケージ管理]]、^1.2.3 が何を許すかは [[セマンティックバージョニング]]。サーバーとフロントを同じ言語で書くなら [[Next.js]] が代表例です。
本番へ載せる
実行環境ごと固めて配るなら [[Docker]]、常時起動のサーバーを持たず関数単位で動かすなら [[サーバーレス・Lambda]] という選択肢があります。どちらもNode.jsの版を明示的に固定でき、「手元では動いたのに本番で動かない」を減らせます。
関連技術とのつながり
- [[JavaScript]] / [[TypeScript]] — Node.jsで動かす言語
- [[REST API]] — Node.jsの代表的な用途
- [[Docker]] — Node.jsアプリのコンテナ化はデプロイの定番
- [[npmとパッケージ管理]] — Node.jsのエコシステムを支える仕組み
- [[並行処理と非同期]] — イベントループが1スレッドで待ちを回す原理
Q: Node.jsのプロセスで、重いCPU計算をその場で同期的に実行すると何が起きる?
- [x] 同じプロセスで処理中の他のリクエストまで待たされる
- [ ] 自動的に別スレッドへ移されるので他に影響しない
- [ ] そのリクエストだけがタイムアウトになる
解説: JavaScriptは1本のスレッドで動くため、待ちではない処理でスレッドを占有すると全リクエストが止まります。重い処理はworker_threadsやキュー経由で別に逃がします。
Q: `package.json` に `"type": "module"` を書いたとき、`.js` ファイルはどう読まれる?
- [ ] CommonJSとして読まれる
- [x] ESモジュールとして読まれる
- [ ] 拡張子に関係なく両方の構文が使えるようになる
解説: 既定では `.js` はCommonJS扱いで、`"type": "module"` を書くとESモジュールになります。`.mjs` / `.cjs` は拡張子側が形式を明示します。
Q: 業務で使うNode.jsのバージョンの選び方として、本文の説明に合うものはどれ?
- [ ] 常に最新の奇数番バージョンを選ぶ
- [x] 偶数番のLTSのうち最新のものを選ぶ
- [ ] バージョンは実行時に自動で決まるので選ぶ必要がない
解説: 偶数番のメジャーバージョンだけがLTSになり、奇数番はサポート期間の短い実験的な版です。