T-CREATOR

Bun で Hello API:超軽量 HTTP サーバを 5 分で公開する

Bun で Hello API:超軽量 HTTP サーバを 5 分で公開する

Web API を構築したいけれど、Node.js は起動が遅い、Docker は重い……そんな悩みを抱えたことはありませんか? Bun は次世代の JavaScript ランタイムとして、圧倒的な速度と開発体験を提供してくれます。 この記事では、Bun を使って最小限の HTTP サーバを構築し、5 分で動かす手順をご紹介しますね。

背景

Node.js と新世代ランタイムの登場

これまで JavaScript のサーバサイド開発といえば Node.js が主流でした。 しかし、近年では Deno や Bun といった新しいランタイムが登場し、パフォーマンスや開発体験の向上が注目されています。

Bun は 2022 年に登場した比較的新しいランタイムですが、以下の特徴により急速に注目を集めているんです。

#項目Node.jsBun
1起動速度標準最大 4 倍高速
2パッケージマネージャnpm/yarn 必要組み込み
3TypeScript サポートトランスパイラ必要ネイティブサポート
4テストランナーJest 等が必要組み込み
5バンドラーWebpack 等が必要組み込み

Bun のアーキテクチャ

Bun の高速性を支える仕組みを図で見てみましょう。

mermaidflowchart TB
    dev["開発者"] -->|コード記述| bunCore["Bun Core<br/>(Zig 言語実装)"]
    bunCore -->|実行| jsEngine["JavaScriptCore<br/>(Safari のエンジン)"]
    bunCore -->|統合| pkgMgr["パッケージマネージャ"]
    bunCore -->|統合| bundler["バンドラー"]
    bunCore -->|統合| testRunner["テストランナー"]

    jsEngine -->|高速実行| app["アプリケーション"]
    pkgMgr -->|依存管理| app
    bundler -->|最適化| app

Bun は Zig 言語で実装されており、JavaScript エンジンには Safari で使われている JavaScriptCore を採用しています。 これにより、従来の V8 エンジンよりも起動が速く、メモリ効率も優れているのです。

課題

従来の HTTP サーバ構築の問題点

Node.js で HTTP サーバを構築する際には、いくつかの課題がありました。

1. セットアップの複雑さ

Node.js で API サーバを構築する場合、以下のような手順が必要でしたね。

mermaidflowchart LR
    start["プロジェクト作成"] --> install1["Express インストール"]
    install1 --> install2["TypeScript インストール"]
    install2 --> config1["tsconfig.json 設定"]
    config1 --> config2["nodemon 設定"]
    config2 --> coding["コーディング開始"]

この一連の流れは、初心者にとってハードルが高く、単純な API を作るだけでも多くの設定が必要でした。

2. パフォーマンスの課題

Node.js の起動時間やリクエスト処理速度は、大規模なアプリケーションでは課題となることがあります。

#指標Node.js + ExpressBun改善率
1起動時間約 200ms約 50ms4 倍高速
2Hello World レスポンス約 5ms約 0.5ms10 倍高速
3メモリ使用量約 30MB約 10MB3 分の 1

3. 開発体験の問題

TypeScript を使う場合、型チェック、トランスパイル、ホットリロードなど、複数のツールを組み合わせる必要がありましたね。 これらの設定は開発速度を低下させる要因となっていました。

解決策

Bun による統合的アプローチ

Bun はこれらの課題を、オールインワンのツールチェーンで解決します。

mermaidflowchart TB
    subgraph traditional["従来のアプローチ"]
        node["Node.js"]
        npm["npm/yarn"]
        ts["TypeScript"]
        bundler1["Webpack/Vite"]
        test1["Jest"]
    end

    subgraph bunApproach["Bun のアプローチ"]
        bunAll["Bun<br/>(すべて統合)"]
    end

    traditional -->|複雑| slow["遅い起動"]
    bunApproach -->|シンプル| fast["高速起動"]

Bun を使うことで、以下のメリットが得られます。

メリット 1:ゼロコンフィグで TypeScript が動く

tsconfig.json の設定なしに、TypeScript ファイルをそのまま実行できます。 トランスパイルも内部で自動的に行われるため、余計な設定ファイルが不要なんですね。

メリット 2:標準 API で HTTP サーバを構築

Bun は Bun.serve() という組み込み API を提供しています。 Express のような外部ライブラリを使わずに、高速な HTTP サーバを構築できるんです。

メリット 3:高速なパッケージインストール

npm や yarn と比較して、最大 25 倍高速にパッケージをインストールできます。 これにより、CI/CD パイプラインの時間短縮にも貢献しますね。

具体例

それでは、実際に Bun で HTTP サーバを構築してみましょう。 5 分で完成する手順を、ステップバイステップで解説していきます。

ステップ 1:Bun のインストール

まずは Bun をインストールします。 macOS または Linux では、以下のコマンド一つで完了します。

bashcurl -fsSL https://bun.sh/install | bash

Windows の場合は WSL2 を使うか、公式サイトから Windows 用のインストーラをダウンロードしてくださいね。

インストールが完了したら、バージョンを確認してみましょう。

bashbun --version

これで 1.0.0 以上のバージョンが表示されれば成功です。

ステップ 2:プロジェクトの初期化

新しいディレクトリを作成し、Bun プロジェクトを初期化します。

bashmkdir hello-bun-api
cd hello-bun-api

次に、Bun のプロジェクト初期化コマンドを実行しましょう。

bashbun init

対話形式でいくつか質問されますが、すべてデフォルト(Enter キー)で問題ありません。 これにより、package.jsontsconfig.json が自動生成されます。

ステップ 3:最小限の HTTP サーバを作成

それでは、実際に HTTP サーバのコードを書いていきましょう。 index.ts ファイルを作成します。

サーバの基本構造

まず、Bun の serve 関数をインポートして、基本的なサーバ構造を作ります。

typescript// Bun の組み込み API をインポート
import { serve } from 'bun';

このインポート文だけで、HTTP サーバに必要な機能がすべて使えるようになります。 Express のような外部ライブラリは不要なんですね。

サーバ設定とハンドラの実装

次に、サーバの設定とリクエストハンドラを実装します。

typescript// HTTP サーバを起動
const server = serve({
  // サーバのポート番号を指定
  port: 3000,

  // リクエストハンドラ関数
  fetch(request) {
    // リクエスト URL を解析
    const url = new URL(request.url);

    // パスに応じてレスポンスを返す
    if (url.pathname === '/') {
      return new Response('Hello, Bun API!');
    }

    // その他のパスは 404 を返す
    return new Response('Not Found', { status: 404 });
  },
});

fetch 関数がすべての HTTP リクエストを処理します。 Request オブジェクトから URL を取得し、パスに応じたレスポンスを返していますね。

サーバ起動メッセージの表示

最後に、サーバが正常に起動したことを確認するためのメッセージを表示します。

typescript// コンソールに起動メッセージを表示
console.log(
  `🚀 Server running at http://localhost:${server.port}`
);

これで、サーバが起動したポート番号を確認できます。

ステップ 4:サーバの起動

作成したサーバを起動してみましょう。 Bun では非常にシンプルなコマンドで実行できます。

bashbun run index.ts

コンソールに以下のようなメッセージが表示されれば成功です。

arduino🚀 Server running at http://localhost:3000

Node.js のように ts-nodenodemon といったツールは不要です。 TypeScript ファイルをそのまま実行できるのが Bun の魅力ですね。

ステップ 5:動作確認

別のターミナルを開いて、API にアクセスしてみましょう。

bashcurl http://localhost:3000

以下のレスポンスが返ってくれば、API サーバが正常に動作しています。

Hello, Bun API!

ブラウザで http:​/​​/​localhost:3000 にアクセスしても、同じメッセージが表示されますよ。

発展:JSON API の実装

より実用的な API にするため、JSON レスポンスを返す例も見てみましょう。

API エンドポイントの拡張

index.ts を編集して、複数のエンドポイントを追加します。

typescriptconst server = serve({
  port: 3000,

  fetch(request) {
    const url = new URL(request.url);

    // ルートパス:テキストレスポンス
    if (url.pathname === '/') {
      return new Response('Hello, Bun API!');
    }

    // /api/status:JSON レスポンス
    if (url.pathname === '/api/status') {
      const data = {
        status: 'ok',
        timestamp: new Date().toISOString(),
        message: 'API is running',
      };

      return new Response(JSON.stringify(data), {
        headers: { 'Content-Type': 'application/json' },
      });
    }

    // その他:404 エラー
    return new Response('Not Found', { status: 404 });
  },
});

この例では、​/​api​/​status にアクセスすると JSON 形式のステータス情報が返ってきます。

JSON API の動作確認

新しいエンドポイントにアクセスしてみましょう。

bashcurl http://localhost:3000/api/status

以下のような JSON レスポンスが返ってきますね。

json{
  "status": "ok",
  "timestamp": "2025-11-16T12:34:56.789Z",
  "message": "API is running"
}

リクエスト処理のフロー図解

これまで実装した API サーバの処理フローを図で整理してみましょう。

mermaidflowchart TD
    client["クライアント"] -->|HTTP リクエスト| server["Bun HTTP サーバ"]
    server -->|URL 解析| router["ルーティング判定"]

    router -->|パス: /| rootHandler["テキストレスポンス<br/>Hello, Bun API!"]
    router -->|パス: /api/status| apiHandler["JSON レスポンス<br/>ステータス情報"]
    router -->|その他| notFound["404 Not Found"]

    rootHandler --> response["Response 生成"]
    apiHandler --> response
    notFound --> response

    response -->|HTTP レスポンス| client

図で理解できる要点

  • すべてのリクエストは fetch 関数で受け取られます
  • URL パスに応じて適切なハンドラが実行されます
  • 各ハンドラは Response オブジェクトを生成して返します

パフォーマンス測定

実際に Bun の速度を体感してみましょう。 Apache Bench を使った簡単な負荷テストを行います。

bash# 1000 リクエスト、同時接続 100 で負荷テスト
ab -n 1000 -c 100 http://localhost:3000/

結果の一例を表で整理してみます。

#指標結果
1秒間リクエスト数約 50,000 req/sec
2平均レスポンスタイム約 0.2ms
3メモリ使用量約 12MB

この数値は Node.js + Express と比較して、約 10 倍の性能を示しています。 軽量な API サーバには最適な選択肢といえるでしょう。

ホットリロードの有効化

開発効率をさらに向上させるため、ファイル変更時の自動再起動を設定しましょう。

Bun には --watch フラグが組み込まれています。

bashbun --watch run index.ts

これで、index.ts を編集して保存すると、自動的にサーバが再起動されます。 nodemon のような追加ツールは不要なんですね。

エラーハンドリングの追加

実用的な API にするため、エラー処理も追加してみましょう。

typescriptconst server = serve({
  port: 3000,

  fetch(request) {
    try {
      const url = new URL(request.url);

      if (url.pathname === '/') {
        return new Response('Hello, Bun API!');
      }

      if (url.pathname === '/api/status') {
        const data = {
          status: 'ok',
          timestamp: new Date().toISOString(),
          message: 'API is running',
        };

        return new Response(JSON.stringify(data), {
          headers: { 'Content-Type': 'application/json' },
        });
      }

      return new Response('Not Found', { status: 404 });
    } catch (error) {
      // エラー発生時は 500 エラーを返す
      console.error('Server error:', error);

      return new Response('Internal Server Error', {
        status: 500,
      });
    }
  },
});

try-catch ブロックで例外をキャッチし、適切なエラーレスポンスを返すことで、サーバの安定性が向上します。

環境変数の活用

ポート番号をハードコーディングせず、環境変数から読み取るように改善しましょう。

typescript// 環境変数からポート番号を取得(デフォルトは 3000)
const port = Number(process.env.PORT) || 3000;

const server = serve({
  port,

  fetch(request) {
    // 前述のハンドラと同じ
    // ...
  },
});

console.log(
  `🚀 Server running at http://localhost:${server.port}`
);

これで、起動時に異なるポートを指定できます。

bashPORT=8080 bun run index.ts

Docker での実行(オプション)

本番環境でのデプロイを見据えて、Docker コンテナ化も見てみましょう。

Dockerfile の作成

プロジェクトルートに Dockerfile を作成します。

dockerfile# Bun の公式イメージを使用
FROM oven/bun:1

# 作業ディレクトリを設定
WORKDIR /app

# package.json をコピー
COPY package.json .

# 依存関係をインストール
RUN bun install

# ソースコードをコピー
COPY . .

# ポート 3000 を公開
EXPOSE 3000

# アプリケーションを起動
CMD ["bun", "run", "index.ts"]

Bun の公式 Docker イメージを使用することで、環境構築が非常にシンプルになりますね。

Docker イメージのビルド

Dockerfile ができたら、イメージをビルドします。

bashdocker build -t hello-bun-api .

コンテナの起動

ビルドしたイメージからコンテナを起動しましょう。

bashdocker run -p 3000:3000 hello-bun-api

これで、Docker コンテナ内で Bun API サーバが動作します。

完成形のディレクトリ構造

最終的なプロジェクト構造を整理してみましょう。

bashhello-bun-api/
├── index.ts          # メインのサーバファイル
├── package.json      # プロジェクト設定
├── tsconfig.json     # TypeScript 設定
├── Dockerfile        # Docker 設定(オプション)
└── README.md         # プロジェクト説明(オプション)

非常にシンプルな構造で、複雑な設定ファイルは最小限に抑えられています。

まとめ

この記事では、Bun を使って HTTP サーバを 5 分で構築する方法をご紹介しました。 重要なポイントを振り返ってみましょう。

Bun の主な利点

  • 高速起動:Node.js の約 4 倍の起動速度
  • シンプルな開発体験:TypeScript をそのまま実行可能
  • オールインワン:パッケージマネージャ、バンドラ、テストランナーが統合
  • 組み込み HTTP サーバ:外部ライブラリ不要で軽量な API を構築

開発のステップ

  1. Bun のインストール(1 コマンド)
  2. プロジェクト初期化(bun init
  3. index.ts でサーバコードを記述
  4. bun run index.ts で起動
  5. JSON API やエラーハンドリングを追加

こんな場面で活躍します

  • プロトタイプ開発や検証用の API サーバ
  • マイクロサービスの軽量なエンドポイント
  • サーバーレス環境での高速な関数実行
  • 開発環境での高速なホットリロード

Bun はまだ比較的新しいランタイムですが、その性能と開発体験の良さから、今後ますます注目されることでしょう。 まずは小さな API サーバから試してみて、その速度を体感してみてくださいね。

関連リンク