Honoとは - 日本発のエッジネイティブフレームワーク
Hono(炎)は、Web標準をベースに構築された超軽量・高速なWebフレームワークです。2021年に和田裕介氏によって開発が始まり、2025年現在ではGitHubで28,000以上のスターを獲得し、66,000以上のプロジェクトで採用されています。
flowchart TB
subgraph Hono["Hono Framework"]
Core["Core<br/>12KB未満"]
Router["RegExpRouter<br/>超高速ルーティング"]
Middleware["ミドルウェア<br/>豊富なエコシステム"]
end
subgraph Runtimes["対応ランタイム"]
CF["Cloudflare Workers"]
Deno["Deno"]
Bun["Bun"]
Node["Node.js"]
AWS["AWS Lambda"]
Fastly["Fastly Compute"]
end
Core --> Runtimes
Router --> Core
Middleware --> Core
Honoの最大の特徴は、同じコードがあらゆるJavaScriptランタイムで動作するという点です。Cloudflare Workers、Deno、Bun、Node.js、AWS Lambda、Fastly Computeなど、18以上のプラットフォームで一切のコード変更なく実行できます。
Honoの核心的特徴
1. 驚異的な軽量性
Honoのhono/tinyプリセットは12KB未満という驚異的な軽さを実現しています。これはExpressの約1/40、Fastifyの約1/20のサイズです。
// hono/tiny を使用した最小構成
import { Hono } from 'hono/tiny'
const app = new Hono()
app.get('/', (c) => c.text('Hello Hono!'))
export default app
この軽量性は、エッジコンピューティングにおいて決定的な優位性をもたらします。コールドスタートが最小化され、ユーザーへのレスポンスが高速化されます。
2. Web標準への準拠
HonoはWeb標準API(Fetch API、Request、Response、URL、Headers等)のみを使用しており、特定のランタイムに依存しません。
import { Hono } from 'hono'
const app = new Hono()
// Web標準のRequest/Responseを直接操作
app.get('/api/user', async (c) => {
const url = new URL(c.req.url)
const userId = url.searchParams.get('id')
// Fetch APIで外部サービスを呼び出し
const response = await fetch(`https://api.example.com/users/${userId}`)
const user = await response.json()
return c.json(user)
})
// Headersの操作
app.get('/api/secure', (c) => {
const authHeader = c.req.header('Authorization')
if (!authHeader) {
return c.json({ error: 'Unauthorized' }, 401)
}
return c.json({ message: 'Authenticated' })
})
export default app
3. 完璧なTypeScriptサポート
Honoは99%以上がTypeScriptで書かれており、型推論が非常に強力です。
import { Hono } from 'hono'
import { z } from 'zod'
import { zValidator } from '@hono/zod-validator'
// スキーマ定義
const userSchema = z.object({
name: z.string().min(1).max(100),
email: z.string().email(),
age: z.number().int().min(0).max(150),
})
type User = z.infer<typeof userSchema>
// 型安全なアプリケーション
const app = new Hono()
// リクエストボディの型が自動推論される
app.post(
'/users',
zValidator('json', userSchema),
async (c) => {
const user = c.req.valid('json') // User型として推論
// user.name, user.email, user.age が型安全にアクセス可能
console.log(`Creating user: ${user.name}`)
return c.json({ id: 1, ...user }, 201)
}
)
// パスパラメータの型定義
app.get('/users/:id', (c) => {
const id = c.req.param('id') // string型
return c.json({ id })
})
export default app
対応プラットフォーム
Honoは2025年現在、以下の18以上のプラットフォームで動作します。
flowchart LR
subgraph Edge["エッジプラットフォーム"]
CF["Cloudflare Workers"]
Fastly["Fastly Compute"]
Vercel["Vercel Edge"]
Netlify["Netlify Edge"]
end
subgraph Serverless["サーバーレス"]
Lambda["AWS Lambda"]
LambdaEdge["Lambda@Edge"]
GCR["Google Cloud Run"]
Azure["Azure Functions"]
end
subgraph Runtime["ランタイム"]
Node["Node.js"]
Deno["Deno"]
Bun["Bun"]
end
subgraph Special["特殊環境"]
SW["Service Workers"]
WASM["WebAssembly"]
end
Hono["Hono"] --> Edge
Hono --> Serverless
Hono --> Runtime
Hono --> Special
各プラットフォームでの起動例
Cloudflare Workers
// src/index.ts
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hello Cloudflare Workers!'))
// Cloudflare WorkersのBindingsを型安全に扱う
type Bindings = {
KV_NAMESPACE: KVNamespace
DB: D1Database
}
const appWithBindings = new Hono<{ Bindings: Bindings }>()
appWithBindings.get('/kv/:key', async (c) => {
const key = c.req.param('key')
const value = await c.env.KV_NAMESPACE.get(key)
return c.json({ key, value })
})
export default app
Deno
// main.ts
import { Hono } from 'npm:hono'
import { serve } from 'https://deno.land/std@0.220.0/http/server.ts'
const app = new Hono()
app.get('/', (c) => c.text('Hello Deno!'))
// Deno.serveで起動
Deno.serve(app.fetch)
Bun
// index.ts
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hello Bun!'))
// Bunのサーバーとして起動
export default {
port: 3000,
fetch: app.fetch,
}
Node.js
// index.ts
import { Hono } from 'hono'
import { serve } from '@hono/node-server'
const app = new Hono()
app.get('/', (c) => c.text('Hello Node.js!'))
serve({
fetch: app.fetch,
port: 3000,
})
console.log('Server running on http://localhost:3000')
ミドルウェアエコシステム
Honoは豊富な組み込みミドルウェアと、サードパーティミドルウェアを提供しています。
組み込みミドルウェア
import { Hono } from 'hono'
import { cors } from 'hono/cors'
import { logger } from 'hono/logger'
import { prettyJSON } from 'hono/pretty-json'
import { secureHeaders } from 'hono/secure-headers'
import { compress } from 'hono/compress'
import { cache } from 'hono/cache'
import { timing } from 'hono/timing'
import { jwt } from 'hono/jwt'
import { basicAuth } from 'hono/basic-auth'
import { bearerAuth } from 'hono/bearer-auth'
import { csrf } from 'hono/csrf'
import { etag } from 'hono/etag'
const app = new Hono()
// ロギング
app.use('*', logger())
// セキュリティヘッダー
app.use('*', secureHeaders())
// CORS設定
app.use('/api/*', cors({
origin: ['https://example.com', 'https://app.example.com'],
allowMethods: ['GET', 'POST', 'PUT', 'DELETE'],
allowHeaders: ['Content-Type', 'Authorization'],
exposeHeaders: ['X-Request-Id'],
maxAge: 86400,
credentials: true,
}))
// レスポンス圧縮
app.use('*', compress())
// JSONの整形表示
app.use('*', prettyJSON())
// キャッシュ制御
app.use('/static/*', cache({
cacheName: 'my-app-cache',
cacheControl: 'max-age=3600',
}))
// CSRF保護
app.use('/form/*', csrf())
// タイミング計測
app.use('*', timing())
// JWT認証
app.use('/api/protected/*', jwt({
secret: 'your-secret-key',
}))
// Basic認証
app.use('/admin/*', basicAuth({
username: 'admin',
password: 'secret',
}))
export default app
カスタムミドルウェアの作成
import { Hono, MiddlewareHandler } from 'hono'
// リクエストIDミドルウェア
const requestId: MiddlewareHandler = async (c, next) => {
const id = crypto.randomUUID()
c.set('requestId', id)
c.header('X-Request-Id', id)
await next()
}
// レート制限ミドルウェア
const rateLimit = (limit: number, window: number): MiddlewareHandler => {
const requests = new Map<string, { count: number; resetTime: number }>()
return async (c, next) => {
const ip = c.req.header('CF-Connecting-IP') || 'unknown'
const now = Date.now()
const record = requests.get(ip)
if (record && now < record.resetTime) {
if (record.count >= limit) {
return c.json({ error: 'Rate limit exceeded' }, 429)
}
record.count++
} else {
requests.set(ip, { count: 1, resetTime: now + window })
}
await next()
}
}
// エラーハンドリングミドルウェア
const errorHandler: MiddlewareHandler = async (c, next) => {
try {
await next()
} catch (err) {
console.error(`Error: ${err}`)
return c.json({
error: 'Internal Server Error',
requestId: c.get('requestId'),
}, 500)
}
}
const app = new Hono()
app.use('*', requestId)
app.use('*', errorHandler)
app.use('/api/*', rateLimit(100, 60000)) // 1分間に100リクエストまで
app.get('/api/data', (c) => {
return c.json({ message: 'Success', requestId: c.get('requestId') })
})
export default app
Express/Fastifyとの比較
パフォーマンス比較
2025年のベンチマークテスト(req/sec、数値が高いほど高速):
| フレームワーク | Cloudflare Workers | Node.js | Bun |
|---|---|---|---|
| Hono | 380,000 | 145,000 | 295,000 |
| Fastify | - | 78,000 | 180,000 |
| Express | - | 15,000 | 45,000 |
サイズ比較
| フレームワーク | パッケージサイズ | 依存関係数 |
|---|---|---|
| Hono (tiny) | 12KB | 0 |
| Hono (full) | 24KB | 0 |
| Fastify | 250KB | 15+ |
| Express | 500KB | 30+ |
機能比較
// Express スタイル
import express from 'express'
const expressApp = express()
expressApp.get('/users/:id', (req, res) => {
const id = req.params.id
res.json({ id })
})
// Hono スタイル(よりモダンで型安全)
import { Hono } from 'hono'
const honoApp = new Hono()
honoApp.get('/users/:id', (c) => {
const id = c.req.param('id')
return c.json({ id })
})
主要な違い
| 特徴 | Hono | Express | Fastify |
|---|---|---|---|
| TypeScript対応 | ネイティブ | 追加型定義が必要 | 良好 |
| エッジ対応 | 完全対応 | 非対応 | 部分対応 |
| マルチランタイム | 18+ | Node.jsのみ | Node.jsのみ |
| Web標準準拠 | 完全 | 独自API | 部分的 |
| コールドスタート | 極小 | 大 | 中 |
実践的なAPI構築例
REST APIの構築
import { Hono } from 'hono'
import { z } from 'zod'
import { zValidator } from '@hono/zod-validator'
// 型定義
interface Todo {
id: number
title: string
completed: boolean
createdAt: string
}
// インメモリストア(実際はDBを使用)
const todos: Todo[] = []
let nextId = 1
// スキーマ定義
const createTodoSchema = z.object({
title: z.string().min(1).max(200),
})
const updateTodoSchema = z.object({
title: z.string().min(1).max(200).optional(),
completed: z.boolean().optional(),
})
// アプリケーション
const app = new Hono()
// 一覧取得
app.get('/todos', (c) => {
const completed = c.req.query('completed')
let result = todos
if (completed !== undefined) {
result = todos.filter((t) => t.completed === (completed === 'true'))
}
return c.json({
todos: result,
total: result.length,
})
})
// 詳細取得
app.get('/todos/:id', (c) => {
const id = parseInt(c.req.param('id'))
const todo = todos.find((t) => t.id === id)
if (!todo) {
return c.json({ error: 'Todo not found' }, 404)
}
return c.json(todo)
})
// 作成
app.post(
'/todos',
zValidator('json', createTodoSchema),
(c) => {
const { title } = c.req.valid('json')
const todo: Todo = {
id: nextId++,
title,
completed: false,
createdAt: new Date().toISOString(),
}
todos.push(todo)
return c.json(todo, 201)
}
)
// 更新
app.patch(
'/todos/:id',
zValidator('json', updateTodoSchema),
(c) => {
const id = parseInt(c.req.param('id'))
const updates = c.req.valid('json')
const index = todos.findIndex((t) => t.id === id)
if (index === -1) {
return c.json({ error: 'Todo not found' }, 404)
}
todos[index] = { ...todos[index], ...updates }
return c.json(todos[index])
}
)
// 削除
app.delete('/todos/:id', (c) => {
const id = parseInt(c.req.param('id'))
const index = todos.findIndex((t) => t.id === id)
if (index === -1) {
return c.json({ error: 'Todo not found' }, 404)
}
const deleted = todos.splice(index, 1)[0]
return c.json(deleted)
})
export default app
RPCスタイルAPI(hono/rpc)
import { Hono } from 'hono'
import { hc } from 'hono/client'
import { z } from 'zod'
import { zValidator } from '@hono/zod-validator'
// サーバー側
const app = new Hono()
.get('/users', (c) => {
return c.json([
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
])
})
.post(
'/users',
zValidator('json', z.object({ name: z.string() })),
(c) => {
const { name } = c.req.valid('json')
return c.json({ id: 3, name }, 201)
}
)
.get('/users/:id', (c) => {
const id = c.req.param('id')
return c.json({ id: parseInt(id), name: 'User' })
})
// 型をエクスポート
export type AppType = typeof app
// クライアント側(完全な型安全性)
const client = hc<AppType>('http://localhost:3000')
// 型安全なAPI呼び出し
async function example() {
// GET /users - レスポンスの型が自動推論
const users = await client.users.$get()
const usersData = await users.json() // { id: number; name: string }[]
// POST /users - リクエストボディも型チェック
const newUser = await client.users.$post({
json: { name: 'Charlie' },
})
const newUserData = await newUser.json() // { id: number; name: string }
// GET /users/:id - パスパラメータも型安全
const user = await client.users[':id'].$get({
param: { id: '1' },
})
const userData = await user.json() // { id: number; name: string }
}
2025年の採用状況
主要な採用企業・プロジェクト
2025年現在、Honoは多くの企業やプロジェクトで採用されています:
- Cloudflare: 公式ドキュメントでHonoを推奨フレームワークとして紹介
- Vercel: Edge Functionsの推奨フレームワークの一つ
- Shopify: エッジでのAPI処理に採用
- 多数のスタートアップ: 高速なAPIバックエンドとして採用増加
GitHubの統計(2025年1月)
- スター数: 28,200+
- 利用プロジェクト数: 66,800+
- コントリビューター: 285人
- 最新バージョン: v4.11.3
エコシステムの成長
flowchart TB
subgraph Core["Hono Core"]
Framework["hono"]
end
subgraph Official["公式パッケージ"]
NodeServer["@hono/node-server"]
ZodValidator["@hono/zod-validator"]
GraphQL["@hono/graphql-server"]
Swagger["@hono/swagger-ui"]
TRPC["@hono/trpc-server"]
end
subgraph Community["コミュニティ"]
Auth["認証ライブラリ"]
ORM["ORM統合"]
Testing["テストユーティリティ"]
end
Core --> Official
Core --> Community
まとめ - なぜHonoを選ぶべきか
2025年、Honoはエッジコンピューティング時代における最適なWebフレームワークとして確固たる地位を築いています。
Honoを選ぶべき理由
- パフォーマンス: 12KB未満の軽量性と超高速ルーティング
- 移植性: 18以上のランタイムで同一コードが動作
- 開発体験: 完璧なTypeScriptサポートと直感的なAPI
- エコシステム: 豊富なミドルウェアとツール群
- 将来性: Web標準への準拠による長期的な安定性
始め方
# プロジェクト作成
npm create hono@latest my-app
# ディレクトリ移動
cd my-app
# 依存関係インストール
npm install
# 開発サーバー起動
npm run dev
Honoは「小さく始めて、大きくスケール」という現代のWeb開発の理想を体現しています。エッジコンピューティング、サーバーレス、マイクロサービスなど、あらゆるユースケースに対応できる柔軟性を持ちながら、シンプルさを失わない設計思想は、多くの開発者に支持される理由となっています。