こんにちは、アジャイル事業部のみちのすけです。AWS re:Invent 2025 に現地参加しています!

この記事は 「Supercharge Lambda with Hono: The lightweight web framework (CNS374)」のセッションレポートです。

AWS Japan の Jo Matsuda さんが、Lambda 上で Web アプリケーションや API を開発する際の課題と、それを解決する軽量フレームワーク「Hono」について紹介されました。

概要

セッションでは、Lambda で Web アプリを構築する際の開発体験の改善について語られました。特に印象的だったのは、たった2行のコードで Hono アプリを Lambda ハンドラーに変換できる という手軽さと、バンドルサイズ 12KB 以下 という軽量性です。

こんな方におすすめ

  • Lambda で Web アプリや API を構築したいと考えている方
  • Express のような馴染みのある開発体験を Lambda で実現したい方
  • TypeScript でエンドツーエンドの型安全性を実現したい方
  • コールドスタートの影響を最小限に抑えたい方

登壇者

  • Jo Matsuda さん(Prototyping Solutions Architect, Amazon Web Services Japan)

登壇者紹介スライド


Lambda で Web アプリをデプロイしたい

セッションは「Lambda で Web アプリや API をデプロイしたい」という要望から始まりました。この要望、実際に聞いたことがある方も多いのではないでしょうか。

Lambda で Web アプリをデプロイしたいという要望

従来のアプローチとしては、API Gateway と複数の Lambda 関数を組み合わせたマイクロサービスパターンがありました。これは責任の分離という点では優れていますが、従来の Web フレームワークに慣れているチームにとっては少し違和感があるかもしれません。ルーティングがエッジ側にあって、ロジックが複数の関数に分散しているという構成ですね。

一方で、最近増えているのが「Lambdalith」パターンです。これは単一の Lambda 関数が複数のルートを管理するという構成で、Lambda Function URLs と組み合わせることでさらにシンプルな構成を実現できます。

Lambdalith パターンのアーキテクチャ図

どちらのアプローチを選ぶかはチームの境界線やスケーリングのニーズによりますが、いずれにしてもまだ課題があります。

Lambda 開発における課題

Jo さんは、Lambda で Web アプリを構築する際に直面する3つの課題を挙げられました。

ハンドラーとイベントの扱い

Lambda のハンドラーとイベントの形式は、従来の Web フレームワークで慣れ親しんだリクエスト/レスポンスモデルとは異なります。この違いが開発体験を損ねる要因になっています。

ルーティングと接着コード

ルーティングやエラーハンドリングなどの接着コードを、馴染みのあるフレームワークなしで一から構築する必要があります。これは結構大変ですよね。

エコシステムとの相性

Lambda Powertools や API Gateway のような優れたサービスはありますが、Lambda 上で Web アプリを構築することは、コンテナベースのスタックと比べてまだ一般的ではありません。そのため、既存の Web ツールを再利用しにくいという課題があります。

Lambda 開発における 3 つの課題

これらの課題に対する解決策として紹介されたのが「Hono」です。

Hono とは

Hono は TypeScript/JavaScript の Web アプリケーションフレームワークです。Express のような馴染みのある API を提供しているのが特徴です。

基本的なコードはこんな感じです。

import { Hono } from 'hono'

const app = new Hono()

app.get('/', (c) => c.json({ message: 'Hello Hono!' }))

app.post('/posts', async (c) => {
  const body = await c.req.json()
  return c.json({ success: true, data: body }, 201)
})

export default app

app.getapp.post という API は Express を使ったことがある方には見覚えがあるのではないでしょうか。c.json() でレスポンスを返し、c.req.json() でリクエストボディを読み取るという、非常に直感的なインターフェースです。

Hono の基本的なコード例

Hono が Lambda に適している理由

Jo さんは Hono が Lambda に適している3つの理由を紹介されました。

1. ランタイム抽象化

Hono の最大の特徴は、一度アプリを書けば複数のランタイムで動作するという点です。Node.js、Deno、Lambda、その他多くのランタイムがサポートされています。

Node.js アダプターを使えばローカルで開発サーバーを起動できますし、ECS などのコンテナベースのスタックにもデプロイできます。もちろん、AWS Lambda アダプターを使えば Lambda 上でも動作します。

重要なのは、Hono アプリ自体はどこでも同じコードだということです。環境ごとにコードを書き直したり、フォークしたりする必要がありません。

2. 豊富なエコシステム

Hono には本番運用に必要なプラグインやミドルウェアが揃っています。

  • @hono/zod-openapi: Zod から OpenAPI スキーマを生成
  • Hono Client (Hono RPC): 型付きクライアントを生成
  • @hono/zod-validator: 型安全なバリデーション
  • @hono/oauth-providers: OAuth 認証
  • @hono/mcp: MCP 統合

特に OpenAPI 生成と型付きクライアントについては、後ほど詳しく紹介がありました。

Hono のエコシステム一覧

3. 軽量性

Hono はデフォルトで軽量です。コードバンドルを小さく保つことができるため、特に Lambda ではコールドスタートの影響を減らせます。

これらの特徴を見ると、Hono が Lambda での開発体験を大きく改善できることが分かりますね。

Lambda で動かすのに必要なコード変更

では、Hono アプリを Lambda で動かすには何が必要なのでしょうか。

Jo さんによると、必要なコード変更はたった2行です。

import { Hono } from 'hono'
import { handle } from '@hono/aws-lambda'  // ← これを追加

const app = new Hono()

app.get('/', (c) => c.json({ message: 'Hello from Hono on Lambda!' }))

app.post('/api/data', async (c) => {
  const body = await c.req.json()
  return c.json({ received: body }, 201)
})

export const handler = handle(app)  // ← これを追加

@hono/aws-lambda パッケージから handle 関数をインポートして、Hono アプリをラップするだけです。これで Hono アプリが Lambda ハンドラーとして動作するようになります。

2 行追加するだけで Lambda ハンドラーに変換

正直、この手軽さには驚きました。たった2行で Lambda 対応できるというのは、かなり開発体験が良さそうですね。

おすすめのプロジェクト構成

Jo さんは、ローカルでの Lambda デバッグに便利なプロジェクト構成も紹介されました。これは実際に日々のプロトタイピング作業で使っているそうです。

lambda/
  api/src/
    app.ts      ← Hono アプリを定義・エクスポート
    handler.ts  ← Hono アプリを Lambda ハンドラーとしてエクスポート
    index.ts    ← Hono アプリを Node.js サーバーとして起動

app.ts

ドメインロジックを記述し、Hono アプリ自体を公開します。

handler.ts

app.ts から Hono アプリをインポートし、@hono/aws-lambda を使って Lambda ハンドラーとしてエクスポートします。

index.ts

app.ts から Hono アプリをインポートし、@hono/node-server プラグインを使って Node.js サーバーとして起動します。

日々の開発では tsx index.ts --watch を実行してローカル開発サーバーを起動し、デプロイ時には handler.ts を指定して Lambda にパッケージングするという流れです。

推奨されるプロジェクト構成

この構成なら、ローカルとLambdaで同じコードを使いながら、それぞれの環境に適した形で実行できますね。開発体験とデプロイの柔軟性を両立できる良い方法だと思います。

Hono のエコシステム:OpenAPI 生成

ここから、Hono の代表的なプラグインについて詳しく紹介がありました。

@hono/zod-openapi

このプラグインを使うと、Zod からOpenAPI スキーマを自動生成できます。Zod は TypeScript エコシステムで非常に有名なバリデーションライブラリですね。

コードの変更はこんな感じです。

import { Hono } from 'hono'
import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi'

// const app = new Hono()  // ← これを削除
const app = new OpenAPIHono()  // ← これに置き換え

// app.get('/', (c) => c.json({ message: 'Hello Hono!' }))  // ← これを削除
app.openapi(helloRoute, (c) => c.json({ message: 'Hello Hono!' }))  // ← これに置き換え

export default app

HonoOpenAPIHono に置き換えて、app.getapp.openapi に変更するだけです。helloRoutecreateRoute 関数の戻り値で、パスとスキーマ(パラメータ、リクエスト/レスポンス)が含まれています。

OpenAPI スキーマを公開するのも簡単です。

app.doc('/doc', {
  openapi: '3.0.0',
  info: {
    version: '1.0.0',
    title: 'My API',
  },
})

これだけで /openapi.json エンドポイントが公開されます。

このスキーマは、クライアント SDK ジェネレーターやドキュメントサイトで利用できます。最近では LLM に渡してシンプルなフロントエンドを生成することもできるそうです。重要なのは、スキーマが常にサーバーの実装と同期しているという点ですね。

Zod から OpenAPI スキーマを生成

OpenAPI スキーマの公開方法

Scalar での API リファレンス

さらに、@scalar/hono-api-reference プラグインを使うと、OpenAPI をインタラクティブな UI として表示できます。

app.get('/scalar', ...)

この UI では、API を直接呼び出したり、cURL、Ruby、Node.js、PHP、Python などのコードをコピーしたりできます。API のテストが簡単にできるのは便利ですね。

OpenAPI 生成がこれだけ簡単にできるのは、かなり魅力的だと思います。ドキュメントの作成と維持が楽になりそうです。

Hono のエコシステム:型付きクライアント(RPC)

次に紹介されたのが、Hono Client(Hono RPC)です。

セッションでは、実際に IDE で型補完が動作する様子がビデオクリップで紹介されました。client. と入力すると、IDE が hello や他のルートを提案してくれるという内容です。これは推測ではなく、契約に基づいた補完だそうです。

仕組み

Hono RPC を使うには、モノレポ構成が推奨されています。

lambda/
  api/src/
    app.ts      ← 型をエクスポート: export type AppType = typeof routes
    handler.ts
    index.ts
frontend/
  client.ts   ← 型をインポート: import type { AppType } from './api/src/app'
              ←               const client = hc<AppType>("/")

サーバー側の app.ts でルートの型をエクスポートし、フロントエンド側の client.ts でその型をインポートして型付きクライアントを作成します。

これにより、IDE やコンパイラが間違ったパスやリクエストパラメータをネットワーク呼び出しの前にキャッチしてくれます。日々の開発作業でこれは本当に助かりますね。

Hono RPC の型付きクライアント

モノレポ構成での型の共有

tRPC のような開発体験を TypeScript ファーストで実現できるというのは、大きな魅力だと思います。フロントエンドとバックエンドの型が完全に同期するのは理想的です。

軽量性の維持

ここまで見てきた機能(Express 風のルーティング、ランタイム抽象化、豊富なエコシステム)を持ちながら、Hono は軽量性を維持しています。

Jo さんによると、バンドルサイズは 12KB 以下 です。もちろん、実際のサイズは自分のコードや依存関係によって変わりますが、ベースとなる Hono パッケージは約10キロバイトだそうです。

軽量性の維持:バンドルサイズ 12KB 以下

これにより、コールドスタートの影響を小さく保つことができます。Lambda で軽量性は重要なポイントですよね。

Lambda Web Adapter との比較

セッションの最後に、Lambda Web Adapter との比較についても触れられました。

Jo さんは、以下のような使い分けを提案されました。

Hono がおすすめのケース

  • 開発体験を優先したい場合
  • TypeScript で新しいアプリを開発する場合

Lambda Web Adapter がおすすめのケース

  • 既に他の言語やフレームワークで構築された Web アプリがある場合
  • それを移行したい場合

それぞれのツールに適した使い方があるということですね。新規で TypeScript プロジェクトを始めるなら、Hono が良さそうです。

まとめ

Hono on Lambda の主な利点をまとめると以下のようになります。

  • 使いやすさ: Express 風のルーティングで、Web フレームワークの人間工学を活用
  • ポータビリティ: 単一の Hono アプリが Node.js、Deno、Lambda など複数の環境で動作
  • プラグイン: Zod からの OpenAPI 生成、Hono RPC による型付きクライアント
  • 軽量性: ベースラインのバンドルサイズは約 12KB で、コールドスタートの影響が小さい

Lambda から離れたくなった場合でも、コンテナベースのスタックや EC2 に簡単に移行できるというのも安心できるポイントですね。

Hono on Lambda のまとめ

個人的には、たった2行のコード変更で Lambda 対応できる手軽さと、エンドツーエンドの型安全性を実現できる点が特に魅力的だと思いました。Lambda で Web アプリを構築する際の選択肢として、かなり有力だと思います。