Skip to content

Hono:為 Edge Runtime 而生的輕量 Web Framework

2026年3月27日 1 分鐘
TL;DR Hono 是專為 Cloudflare Workers、Deno、Bun 等 edge runtime 設計的 Web framework,比 Express 輕一個數量級,原生支援 Web Standard API,是 edge 環境下的首選。
目錄
  1. 它是什麼
  2. 為什麼不用 Express
  3. 核心特性
  4. 架構分層
  5. 什麼時候選 Hono
  6. Tradeoffs
  7. 更新紀錄
  8. 參考資料

🌏 English version

Express 在 Node.js 上統治了超過十年,但在 Cloudflare Workers 上跑 Express 從一開始就是錯的。Workers 執行在 V8 Isolate 裡,不是 Node.js 環境,Express 的大量 Node.js API 依賴根本跑不動。Hono 就是為了解決這個問題而生的。

它是什麼

Hono 是一個超輕量的 Web framework,設計目標是在任何 JavaScript runtime 上跑:

  • Cloudflare Workers
  • Deno
  • Bun
  • Node.js(也支援,但不是主戰場)
  • AWS Lambda

官方標的數字是 hono/tiny preset minify 後小於 14 kB(不是整包 Hono——middleware 與 adapter 只有用到才會被打包進去)。零依賴,完全用 Web Standard API 寫(RequestResponseURL)。

NobodyClimb 的後端就是用 Hono,部署在 Cloudflare Workers 上。選它的原因很直接:沒有別的 framework 在 Cloudflare Workers 上有同樣的 DX 和完整度。

為什麼不用 Express

Express 的問題不是 API 設計不好,而是它預設 Node.js 存在:

  • req.socketres.end()Buffer 都是 Node.js-only API
  • Bundle size 吃掉 Workers 的 script 大小上限 一大塊(免費與付費方案的上限不同:壓縮後 3 MB/10 MB,另有兩方案共通的壓縮前 64 MB 上限)
  • 沒有原生的 async/await middleware 支援,錯誤處理容易漏

在 Cloudflare Workers 環境下,你需要:

  1. 能直接操作 env.DB(D1)、env.KV(KV)、env.R2(R2)的 context
  2. 支援 ctx.waitUntil() 做背景任務
  3. Bundle size 盡量小

Hono 對這些都有原生支援。

核心特性

Routing 語法跟 Express 幾乎一樣,學習曲線幾乎是零:

import { Hono } from 'hono'

const app = new Hono()

app.get('/posts/:id', (c) => {
  const id = c.req.param('id')
  return c.json({ id })
})

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

export default app

Middleware 是 async-first,不會有 Express 裡 next() 忘記呼叫導致 hang 住的問題:

import { Hono } from 'hono'
import { jwt } from 'hono/jwt'
import { cors } from 'hono/cors'

const app = new Hono<{ Bindings: Env }>()

app.use('*', cors())
app.use('/api/*', jwt({ secret: 'secret' }))

app.get('/api/me', (c) => {
  const payload = c.get('jwtPayload')
  return c.json({ userId: payload.sub })
})

Cloudflare Workers bindings 透過 typed context 存取

type Bindings = {
  DB: D1Database
  KV: KVNamespace
  AI: Ai
}

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

app.get('/search', async (c) => {
  const query = c.req.query('q')
  // c.env.DB 是 D1,完全有型別
  const results = await c.env.DB
    .prepare('SELECT * FROM posts WHERE title LIKE ?')
    .bind(`%${query}%`)
    .all()
  return c.json(results)
})

OpenAPI 整合(hono-openapi)

NobodyClimb 用 hono-openapi 自動生成 OpenAPI spec,API 文件和實作保持同步:

import { describeRoute } from 'hono-openapi'
import { resolver } from 'hono-openapi/zod'

app.get(
  '/posts/:id',
  describeRoute({
    description: '取得單篇貼文',
    responses: {
      200: { content: { 'application/json': { schema: resolver(PostSchema) } } }
    }
  }),
  async (c) => {
    const id = c.req.param('id')
    // ...
  }
)

Scalar UI 掛在 /api/v1/docs,開發時直接在瀏覽器測 API。

架構分層

NobodyClimb 的 Hono 後端分三層:

routes → services → repositories

Routes 只管 OpenAPI 描述和 request validation,services 放業務邏輯,repositories 做 D1 查詢。這跟 Express 的分層方式一樣,Hono 沒有強制你用特定的架構風格。

什麼時候選 Hono

適合的情境:

  • 部署在 Cloudflare Workers、Deno Deploy、Bun
  • 需要小 bundle size(Workers 的限制)
  • 想要 Web Standard API 相容的 codebase
  • 從 Express 遷移,想要熟悉的 API 語法

不適合的情境:

  • 已經在 Node.js 環境而且沒有遷移計畫
  • 需要大量 Express 生態的 middleware(passport.js、multer 等)
  • 團隊對 edge runtime 概念不熟,學習成本會轉移到其他地方

Tradeoffs

Hono 很輕,但輕意味著你要自己組裝更多東西。Express 的生態有十幾年的 middleware 積累,很多需求有現成解法;Hono 的生態還在成長,遇到邊緣需求可能要自己寫。

另一個要注意的是:Workers 環境有很多限制(沒有檔案系統、沒有 TCP socket 直接存取、CPU 時間與記憶體上限)。這些不是 Hono 的問題,是 Workers 的限制——但選了 Hono 通常意味著你也選了 Workers,所以要一起考慮。

更新紀錄

  • 2026-08-19:對照官方文件逐篇查證翻新,移除易腐內容,並收進「Cloudflare 邊緣tech stack」系列

參考資料