---
title: "Hono vs FastAPI（Python）の違い｜Honoとは・メリット・使い方を実行結果で比較【Hono 4.13】"
url: "https://www.issoh.co.jp/column/details/3001/"
published: 2024-07-09
updated: 2026-09-29
categories: ["Webシステム"]
publisher: "株式会社一創"
---

# Hono vs FastAPI（Python）の違い｜Honoとは・メリット・使い方を実行結果で比較【Hono 4.13】

Hono（ほの）は、Web標準のRequest／Response APIの上に作られたTypeScript製のWebフレームワークです。名前は日本語の「炎」に由来し、同じコードがCloudflare Workers、Deno、Bun、Node.js、AWS Lambdaなどで動きます。2026年9月29日時点のnpm最新版は4.13.11です。

「FastAPIとHonoのどちらを使うか」は、実のところ「PythonとTypeScriptのどちらでAPIを書くか」とほぼ同じ問いになります。この記事では、同じユーザー登録APIを両方で書いて実行した結果（検証エラーの応答、OpenAPIの出力、型の共有）で違いを比べ、そのうえでHonoの始め方、JWT認証、テスト、デプロイ先ごとの入口を説明します。

## まとめ：Honoの要点とFastAPIとの選び分け

- **Honoとは**：Web標準APIだけで書かれた、依存パッケージ0のTypeScript製Webフレームワーク。Pythonでは使えません。
- **FastAPIとの最大の違い**：言語と実行環境です。FastAPIはPython＋ASGIサーバー、Honoはエッジを含むJavaScriptランタイムで動きます。
- **検証とドキュメント**：FastAPIは検証失敗で422を返し、OpenAPI 3.1.0と/docsを標準で出します。Honoは@hono/zod-openapiを足すと、400の応答とOpenAPI 3.0／3.1の出力を得られます。
- **Honoを選ぶ場面**：Cloudflare Workersなどエッジで動かしたい、フロントエンドとTypeScriptの型を共有したいとき。
- **FastAPIを選ぶ場面**：PyTorchやpandasなどPythonのライブラリを同じプロセスで呼ぶAPI、Pythonしか書かないチーム。
- **JWTの注意**：Hono 4.11.4（2026年1月）以降、jwtミドルウェアは`alg`の指定が必須です。古い記事のコードは起動時に例外になります。

## Honoの定義と動作するランタイム

Honoはnpmで2021年12月に0.0.1が公開され、2024年2月9日にv4.0.0が出ました。作者はYusuke Wada氏です。公式ドキュメントが挙げる動作先は、Cloudflare Workers、Fastly Compute、Deno、Bun、Vercel、Netlify、AWS Lambda、Lambda@Edge、Node.jsです。

多くのランタイムで同じコードが動くのは、HonoがNode.js固有のAPIに頼らず、どのランタイムにもあるWeb標準のRequestとResponseだけを扱うからです。npmのpackage.jsonに依存パッケージは1つもなく、公式によると`hono/tiny`プリセットはminify後14KB未満に収まります。起動の軽さが効くサーバーレスやエッジで選ばれる理由はここにあります。

書き味はExpressに近く、`app.get('/', (c) => c.text('Hello'))`のようにルートとハンドラを並べます。CORS、JWT、Basic認証、ロガー、ETagなどのミドルウェアは本体に同梱されており、別パッケージを探す必要はありません。

## HonoとFastAPIの違いを比較表で整理

同じ「名前と年齢を受け取ってユーザーを作るAPI」を両方で書き、2026年9月29日に手元で実行しました。Hono側は hono 4.13.11 と @hono/zod-openapi 1.6.3（Node.js v26.5.0）、FastAPI側は fastapi 0.141.1 と pydantic 2.13.5（Python 3.12）です。

| 比較軸             | Hono                       | FastAPI             |
| --------------- | -------------------------- | ------------------- |
| 言語              | TypeScript／JavaScript      | Python 3.10以上       |
| 実行環境            | Workers・Deno・Bun・Node.jsなど | ASGIサーバー（Uvicorn等）  |
| 入力検証            | Zodなど（ミドルウェアで追加）           | Pydantic（標準）        |
| 検証失敗時の応答        | 400（zod-openapi既定）         | 422                 |
| OpenAPI出力       | 3.0／3.1（追加パッケージ）           | 3.1.0（標準）           |
| ドキュメント画面        | @hono/swagger-uiを追加        | /docs・/redocが標準     |
| クライアントとの型共有     | RPC（hono/client）           | OpenAPIからコード生成      |
| 最新版（2026-09-29） | 4.13.11                    | 0.141.1（2026-07-29） |

### 検証エラーの応答：Honoは400、FastAPIは422

空の名前と文字列の年齢（`{"name": "", "age": "x"}`）を送ると、FastAPIは422を返し、`detail`配列に`string_too_short`と`int_parsing`の2件を入れます。@hono/zod-openapiで書いたHonoは400を返し、本文は`{"success":false,"error":{"name":"ZodError",...}}`です。

既存のFastAPIをHonoへ移すと、フロントエンドが「422なら入力エラー」と判定しているコードが素通りになります。移行時は、Hono側で`defaultHook`を設定して422と独自形式を返すか、クライアントの判定を400に合わせるかを先に決めてください。

### APIドキュメント自動生成の手間

FastAPIは何も足さずに`/openapi.json`（openapi 3.1.0）と、Swagger UIの`/docs`、ReDocの`/redoc`を配信します。型ヒントとPydanticモデルを書いた時点でドキュメントも揃う点は、FastAPIが明確に勝っています。

Honoの本体にはOpenAPI生成の機能がありません。@hono/zod-openapiでルートをスキーマ付きで定義し、`app.doc()`で3.0、`app.doc31()`で3.1を出力し、画面は@hono/swagger-uiで足します。ルートを`createRoute()`で書き直す手間がかかる代わりに、検証・型・ドキュメントの定義が1か所にまとまります。ZodスキーマからOpenAPIを作る方法の選び分けは[ZodからOpenAPIを生成する方法](/tech/details/5646/)で詳しく比べています。

### 速度比較の前提：402,820 ops/secはルーター同士の数値

Hono公式の「最速」は、Cloudflare Workers向けルーター同士の比較（Honoが402,820 ops/sec）です。FastAPIとの比較ではありません。実際のAPIの応答時間は、DBや外部APIの待ち時間と、Uvicornのワーカー数やエッジの配置で大きく変わります。速度だけを理由に言語を乗り換えるのはおすすめしません。

## Hono Pythonの有無とPython Workers×FastAPIの構成

HonoはJavaScriptランタイム専用で、Python版はありません。「hono python」で探している場合、Pythonで同じ役割を担うのはFastAPIです。FastAPIの基本と起動方法は[FastAPIとは｜最短で動かす手順とasync/defの使い分け](/tech/details/3859/)にまとめています。

「Honoのようにエッジで動かしたいが、書くのはPython」という要件なら、Cloudflare WorkersのPython Workersが使えます。Cloudflareの公式ドキュメントはFastAPIを対応パッケージとして挙げ、Workers側が用意するASGIサーバーにアプリを渡す書き方を示しています。

```
# src/main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

from workers import asgi
Default = asgi.entrypoint(app)
```

wrangler.jsoncに`"compatibility_flags": ["python_workers"]`を書き、pyproject.tomlは`requires-python = ">=3.13"`とし、`uv run pywrangler dev`でローカル起動します。Cloudflare Workers自体の料金や無料枠は[Cloudflare Workersとは？対応言語・無料枠・使い方・料金](/tech/details/6760/)を参照してください。

## Honoのメリットと採用を見送るべき条件

### Honoを選ぶ4つの理由

- **配置先を後から変えられる**：Node.jsで作ったAPIを、アダプターと入口ファイルの差し替えだけでWorkersやLambdaへ移せます。
- **フロントエンドと型を共有できる**：RPC機能で、サーバーのルート定義からクライアントの型が生成されます（後述）。
- **依存が少ない**：本体の依存パッケージは0。サプライチェーンの監査対象が小さく済みます。
- **ミドルウェアが同梱**：CORS、JWT、JWK、Basic認証、CSRF、Secure Headers、Timeoutなどが`hono/cors`のようなパスで読み込めます。

### FastAPIのままにすべき条件

次のどれかに当てはまるなら、Honoへ移す利点より損失の方が大きくなります。

- 推論やデータ処理でPyTorch、pandas、scikit-learnを同じプロセスから呼んでいる。Honoにすると、別のPythonサービスを立ててHTTP越しに呼ぶ構成になります。
- チームにTypeScriptを書く人がいない。
- OpenAPIドキュメントを追加の作業なしで出したい。Honoではルート定義の書き直しが要ります。
- ORMや管理画面まで一式ほしい。Hono本体にもFastAPIにも無いので、その場合はDjangoなど別の選択肢を[Webアプリケーションフレームワークとは？主要フレームワーク比較と選び方](/column/details/2489/)で比べてください。

## Honoの始め方：create-honoから最初のAPIまで

雛形は`npm create hono@latest my-app`で作り、表示されるテンプレートから配置先（`nodejs`、`cloudflare-workers`、`bun`など）を選びます。Node.jsで動かす最小構成は次のとおりです。

```
import { serve } from '@hono/node-server'
import { Hono } from 'hono'
import { cors } from 'hono/cors'

const app = new Hono()

app.use('/api/*', cors({ origin: 'http://localhost:5173' }))
app.get('/api/hello', (c) => c.json({ message: 'Hello Hono!' }))

serve({ fetch: app.fetch, port: 3000 })
```

このコードを実行し、Originヘッダー付きで`/api/hello`を叩くと、200と`Access-Control-Allow-Origin: http://localhost:5173`が返りました。

Node.jsの対応版には注意が要ります。公式のNode.jsページは「18.x以上」と書いていますが、@hono/node-server 2.1.3のpackage.jsonは`"node": ">=20"`を要求します。Node.js 18の環境ではアダプターのインストール時に警告が出るので、20以上に上げてから始めてください。

## zod-openapiによる検証・型・OpenAPIの一元定義

比較表の結果を出したHono側のコードです。リクエストの形をZodで1回書けば、検証、ハンドラ内の型、OpenAPIの出力が揃います。

```
import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi'
import { swaggerUI } from '@hono/swagger-ui'

const app = new OpenAPIHono()

const route = createRoute({
  method: 'post',
  path: '/users',
  request: {
    body: {
      content: {
        'application/json': {
          schema: z.object({ name: z.string().min(1), age: z.number().int() }),
        },
      },
    },
  },
  responses: {
    201: {
      content: { 'application/json': { schema: z.object({ id: z.number(), name: z.string() }) } },
      description: 'created',
    },
  },
})

app.openapi(route, (c) => {
  const { name } = c.req.valid('json') // name は string 型
  return c.json({ id: 1, name }, 201)
})

app.doc('/doc', { openapi: '3.0.0', info: { title: 'API', version: '1.0.0' } })
app.get('/ui', swaggerUI({ url: '/doc' }))
```

FastAPIで同じことを書くと、Pydanticモデルと関数の型ヒントだけで済みます。FastAPIのSwagger UIの表示や本番での無効化は[FastAPIのSwagger UI（/docs）自動生成](/tech/details/2246/)で扱っています。

```
from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()

class UserIn(BaseModel):
    name: str = Field(min_length=1)
    age: int

@app.post("/users", status_code=201)
def create_user(user: UserIn):
    return {"id": 1, "name": user.name}
```

## RPCでクライアントと型を共有する手順と注意点

HonoのRPCは、サーバーのアプリの型（`typeof app`）をクライアントに渡し、`hc`関数でエンドポイントを型付きで呼ぶ仕組みです。FastAPIでフロントエンドの型を得るにはOpenAPIからコード生成を挟みますが、Honoは同じリポジトリ内なら生成の工程が要りません。

```
// server.ts
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'

const app = new Hono().post(
  '/todos',
  zValidator('json', z.object({ title: z.string() })),
  (c) => c.json({ id: 1, title: c.req.valid('json').title }, 201)
)
export type AppType = typeof app

// client.ts
import { hc } from 'hono/client'
import type { AppType } from './server'

const client = hc<AppType>('http://localhost:3000')
const res = await client.todos.$post({ json: { title: 'buy milk' } })
if (res.status === 201) {
  const data = await res.json() // { id: number; title: string }
  console.log(data.id, data.title)
}
```

TypeScript 7.0.2の`tsc`で確かめたところ、`title`を`titel`と打ち間違えると「TS2561: Object literal may only specify known properties」でコンパイルが止まりました。サーバー側の項目名を変えたときに、クライアントの呼び出し箇所がビルドで見つかるということです。

つまずきやすい点が2つあります。1つは、`typeof app`を渡すならルートを`new Hono().post(...)`のようにメソッドチェーンで書く必要があることです。`app.post(...)`を別の文に分けて戻り値を捨てると`typeof app`にルートの型が残らず、tscでは`client`が`unknown`になります（TS18046）。別の文で書く場合は、公式の例のように`const route = app.post(...)`と戻り値を受けて`typeof route`を渡します。もう1つは、zValidatorを挟んだルートでは`res.json()`の型が「成功時の本文」と「検証エラー」の合併型になることです。上の例のように`res.status`か`res.ok`で分岐しないと、`data.id`の参照が「TS2339: Property ‘id’ does not exist」になります。

## JWT認証の実装とalg必須化（v4.11.4）

JWTの検証は同梱の`hono/jwt`ミドルウェアで書けます。2026年1月13日のv4.11.4で、JWTの署名アルゴリズムの取り違え（algorithm confusion、GHSA-f67f-6cw9-8mq4）を防ぐため、jwtとjwkの両ミドルウェアで`alg`が必須オプションになりました。

```
import { Hono } from 'hono'
import { jwt } from 'hono/jwt'
import type { JwtVariables } from 'hono/jwt'

const app = new Hono<{ Variables: JwtVariables }>()

app.use('/auth/*', jwt({ secret: process.env.JWT_SECRET!, alg: 'HS256' }))
app.get('/auth/me', (c) => c.json(c.get('jwtPayload')))
```

4.13.11で`alg`を省くと、`jwt()`を呼んだ時点で「JWT auth middleware requires options for “alg”」という例外が出ました。2025年以前の解説記事のコードをそのまま貼ると起動しないのはこのためです。トークンなしでアクセスすると、401と`WWW-Authenticate: Bearer ... error="invalid_request"`が返ります。Cloudflare Workersでは`process.env`ではなく、ミドルウェア内で`jwt({ secret: c.env.JWT_SECRET, alg: 'HS256' })`を組み立てて呼ぶのが公式の書き方です。

RS256などの公開鍵方式は、2024年4月のv4.2.0で対応アルゴリズムが3種から13種に増えた時点で使えるようになりました。「HonoはRSAの検証が苦手」という情報は古いものです。Auth0やCognitoのようにJWKSのURLで公開鍵を配る認証基盤なら、`hono/jwk`の`jwk({ jwks_uri, alg: ['RS256'] })`を使います。JWKミドルウェアはHS256などの共通鍵方式を拒否し、トークンのヘッダーに`kid`が無いと検証しません。

## テストの書き方：app.requestとtestClient

Honoのアプリはサーバーを起動せずにテストできます。`app.request('/users', { method: 'POST', body: ... })`がResponseを返すので、VitestやJestからそのまま検証できます。この記事の実行結果もこの方法で取りました。

型付きで呼びたい場合は`hono/testing`の`testClient(app)`を使います。RPCと同じくメソッドチェーンで書いたルートにだけ型が付き、`client.search.$get({ query: { q: 'hono' } })`のように呼べます。FastAPIの`TestClient`と同じ位置づけですが、FastAPI側は`fastapi`単体で入れた場合、テスト用HTTPクライアント（httpx）を別途インストールする必要があります（`fastapi[standard]`には同梱）。なおStarlette 1.7.0以降は、httpxのままだとhttpx2への移行を促す非推奨の警告が出ます。

## デプロイ先別の入口：Cloudflare Workers・Azure Functions・Node.js

Honoのアプリ本体は共通で、配置先ごとに変わるのは入口ファイルとアダプターです。

| 配置先                | 入口                              | 前提                         |
| ------------------ | ------------------------------- | -------------------------- |
| Cloudflare Workers | `export default app`            | Wrangler                   |
| Node.js            | @hono/node-serverの`serve()`     | 2.x系はNode.js 20以上          |
| Azure Functions    | @marplex/hono-azurefunc-adapter | Functions V4・Node.js 22／24 |
| AWS Lambda         | @hono/aws-lambdaの`handle()`     | 本体のhono/aws-lambdaはv5で削除予定 |

2026年9月28日の4.13.10で、ランタイム別のアダプターは本体から別パッケージ（@hono/aws-lambda、@hono/bun、@hono/deno、@hono/cloudflare-workers、@hono/lambda-edge、@hono/netlify、@hono/vercel、@hono/service-worker）へ分離されました。本体の`hono/aws-lambda`などは4.13.11でも読み込めますが非推奨で、v5で削除されます。AWS Lambdaでは@hono/aws-lambda（1.0.0）の`handle()`を使ってください。また4.13.11では、`serveStatic`がパスを二重にデコードし、静的パスに掛けたミドルウェアを迂回できる脆弱性（GHSA-5r4p-p66f-jhc7）が修正されました。Bun・Deno・Cloudflare Workersで静的ファイルを配信するなら、この版以上を使ってください。

Azure Functionsは、公式ドキュメントも「最初からAzure Functions向けに作ったわけではない」と断ったうえで、サードパーティのアダプター（@marplex/hono-azurefunc-adapter。最終リリースは2024年10月の1.0.1）を案内しています。`app.http()`の`route`に`{*proxy}`を指定して全パスをHonoへ渡し、ハンドラに`azureHonoHandler(honoApp.fetch)`を渡します。

Azure Functionsでは、既定でURLの先頭に`/api`が付きます。host.jsonの`extensions.http.routePrefix`を空文字にするか、Hono側のルートをすべて`/api`始まりにするかのどちらかが必要です。ここを忘れると、Node.jsで動かしていたときと同じURL（例：`/users`）へのリクエストが、`func start`でのローカル実行でもAzure上でも404になります。Honoの上にファイルベースのルーティングを載せたい場合は[HonoXとは？Hono×Viteのメタフレームワーク](/tech/details/3614/)も検討してください。

## よくある質問

### HonoとFastAPIはどちらを選ぶべきですか？

書く言語で決めるのが基本です。Pythonのライブラリを同じプロセスで使うAPIならFastAPI、エッジで動かしたい場合やTypeScriptのフロントエンドと型を共有したい場合はHonoを選んでください。

### HonoはPythonで使えますか？

使えません。HonoはJavaScriptランタイム専用です。Pythonでエッジに配置したい場合は、Cloudflare Python WorkersでFastAPIを動かす方法があります。

### Honoのメリットは何ですか？

依存パッケージが0で軽く、同じコードをCloudflare Workers、Deno、Bun、Node.jsなどで動かせることです。RPCでクライアントとサーバーの型を共有できる点も、TypeScriptで開発するチームには大きな利点です。

### HonoでJWT認証は実装できますか？

できます。同梱の`hono/jwt`ミドルウェアで検証でき、v4.11.4以降は`alg`の指定が必須です。RS256などの公開鍵方式にも対応し、JWKSのURLから鍵を取る場合は`hono/jwk`が受け持ちます。

### HonoでもSwagger UIのようなAPIドキュメントを出せますか？

出せます。@hono/zod-openapiでOpenAPIの定義を生成し、@hono/swagger-uiで画面を配信します。FastAPIと違い標準では付いていないため、パッケージの追加とルート定義の書き直しが必要です。

## 関連記事

- [FastAPIとは｜最短で動かす手順とasync/defの使い分け【2026年版】](/tech/details/3859/)
- [HonoXとは？Hono×Viteのメタフレームワークの特徴・使い方・採用判断](/tech/details/3614/)
- [Cloudflare Workersとは？対応言語・無料枠・使い方・料金を最新版で総まとめ](/tech/details/6760/)
- [ZodからOpenAPIを生成する方法｜zod-to-openapiとZod 4ネイティブ変換・ライブラリの選び分け](/tech/details/5646/)
- [Webアプリケーションフレームワークとは？主要フレームワーク比較と選び方【2026年版】](/column/details/2489/)

---

出典: [Hono vs FastAPI（Python）の違い｜Honoとは・メリット・使い方を実行結果で比較【Hono 4.13】](<https://www.issoh.co.jp/column/details/3001/>)（株式会社一創）
