アダプタとデプロイ

Hono のコアは Web 標準(Request/Response)。各ランタイムが少しずつ違うので、 その差を埋めるアダプタで繋ぐ。「コードはそのまま、デプロイ先だけ変える」が現実になる。

主なアダプタ一覧

ランタイムアダプタ備考
Cloudflare Workers不要(Hono コア)標準対応
Cloudflare Pages不要(_worker.js / Pages Functions)標準対応
Bun不要(Bun.serve)標準対応
Deno不要(Deno.serve)標準対応
Node.js@hono/node-serverfetch を Node に翻訳
AWS Lambdahono/aws-lambdaAPI Gateway / Function URL
Lambda@Edgehono/lambda-edgeCloudFront
Vercel Edge不要(標準 Web Handler)標準対応
Netlifyhono/netlifyEdge Functions
Fastly Computehono/fastly
Service Worker不要ブラウザ内実行も可能

Cloudflare Workers

src/index.ts
import { Hono } from "hono"

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

const app = new Hono<{ Bindings: Bindings }>()
app.get("/", (c) => c.text("Hello from CF Workers"))

export default app

wrangler.toml

name = "my-hono-app"
main = "src/index.ts"
compatibility_date = "2026-05-01"

[[d1_databases]]
binding = "DB"
database_name = "my-db"
database_id = "..."

[[kv_namespaces]]
binding = "KV"
id = "..."

[ai]
binding = "AI"

デプロイ

npm install -g wrangler
wrangler login
wrangler deploy

Cloudflare Pages(Functions)

既存の静的サイトに API を足したい時。functions/[[path]].ts でキャッチオール。

functions/api/[[path]].ts
import { Hono } from "hono"
import { handle } from "hono/cloudflare-pages"

const app = new Hono().basePath("/api")
app.get("/hello", (c) => c.text("Hello"))

export const onRequest = handle(app)

Bun

src/index.ts
import { Hono } from "hono"

const app = new Hono()
app.get("/", (c) => c.text("Bun + Hono"))

export default app
bun run --hot src/index.ts

Deno

import { Hono } from "npm:hono"

const app = new Hono()
app.get("/", (c) => c.text("Deno + Hono"))

Deno.serve(app.fetch)
deno run --allow-net main.ts

Deno Deploy

deno deploy CLI または Deno Deploy ダッシュボードで GitHub 連携。

Node.js

npm install hono @hono/node-server
import { serve } from "@hono/node-server"
import { Hono } from "hono"

const app = new Hono()
app.get("/", (c) => c.text("Node + Hono"))

serve({ fetch: app.fetch, port: 3000 }, (info) => {
  console.log(`http://localhost:${info.port}`)
})

静的ファイル

import { serveStatic } from "@hono/node-server/serve-static"
app.use("/static/*", serveStatic({ root: "./public" }))

AWS Lambda

import { Hono } from "hono"
import { handle } from "hono/aws-lambda"

const app = new Hono()
app.get("/", (c) => c.text("Lambda + Hono"))

export const handler = handle(app)

SST / AWS CDK / Serverless Framework でデプロイ。Function URL(API Gateway 不要)でも動く。

Vercel

api/[[...path]].ts
import { Hono } from "hono"

const app = new Hono().basePath("/api")
app.get("/hello", (c) => c.json({ ok: true }))

export const config = { runtime: "edge" }      // Edge Runtime
export default app.fetch

Netlify

netlify/edge-functions/api.ts
import { Hono } from "https://deno.land/x/hono/mod.ts"
import { handle } from "https://deno.land/x/hono/adapter/netlify/mod.ts"

const app = new Hono()
app.get("*", (c) => c.text("Netlify Edge"))

export default handle(app)
export const config = { path: "/api/*" }

環境変数の扱いの違い

環境アクセス
Cloudflare Workersc.env.MY_VAR
Bun / Deno / Nodeprocess.env / Bun.env / Deno.env.get(...)
Vercelprocess.env
Lambdaprocess.env

移植性のために、初期化時に環境変数を吸収するレイヤを作っておくと楽:

function getEnv(c: any, key: string) {
  if (c.env && key in c.env) return c.env[key]
  if (typeof process !== "undefined" && process.env[key]) return process.env[key]
  return undefined
}

WebSocket

WebSocket 対応はランタイム依存:

テスト

import { describe, it, expect } from "vitest"
import app from "../src/index"

describe("API", () => {
  it("GET /", async () => {
    const res = await app.request("/")
    expect(res.status).toBe(200)
    expect(await res.text()).toBe("Hello")
  })

  it("POST /users", async () => {
    const res = await app.request("/users", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ name: "A", email: "a@b.c" }),
    })
    expect(res.status).toBe(201)
  })
})

app.request() でランタイム不要のテストが可能。fetch を直接受ける形なので超簡単。

マルチランタイム同時対応

同じコードを複数ランタイムに出すパターン。エントリポイントだけ分ける:

src/
├── app.ts              ← 共通の Hono アプリ
├── cloudflare.ts       ← export default app
├── node.ts             ← serve(app)
└── lambda.ts           ← handle(app)

ローカル開発

迷ったら

- サーバレスでフリーティアを最大化: Cloudflare Workers
- Bun のパフォーマンス: Bun + Fly.io / Railway
- 既存の Node エコシステム: Node + Render / Railway
- AWS が会社標準: Lambda + Function URL