Go を Cloudflare Workers で動かす

Cloudflare Workers は V8 isolate 上で JS と WASM を動かす実行系で、ネイティブな Go ランタイムは持たない。だから「Workers で Go」= Go を WASM にコンパイルし、JS グルーから呼ぶこと。実用上の定番は TinyGo + [syumai/workers]。

なぜそのまま動かないか / なぜ TinyGo か

WASM は I/O の標準インターフェースを持たない。fetch イベント・ネットワーク・KV などは JS 側で受けて wasm の export 関数を呼ぶ(または wasm が import する)しかない。そしてサイズの壁:

標準 Go (go build)TinyGo
wasm 出力GC + ランタイム同梱で大きい(数 MB)専用の小型ランタイムで ~1MB 以下
Workers サイズ上限無料 ~3MB / 有料 10MB(gzip 後)に当たりやすい余裕で収まる
プラン大依存だと有料前提無料でも可
互換性Go 標準ライブラリほぼ全部一部制限(reflect・net 等に制約)

→ Workers のバンドルサイズ上限が効くので、ほぼ TinyGo 一択。サイズはそのまま isolate のコールドスタート/コストにも響く。

2つの経路

  1. syumai/workers(デファクト) — net/http 風のハンドラを Go で書き、TinyGo で wasm 化、wrangler + JS グルーでデプロイ。D1 / KV / R2 などの Cloudflare バインディングに Go の API でアクセスできる。テンプレ worker-tinygo 推奨。
    // syumai/workers: net/http ハンドラがそのまま動く
    func main() {
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
            fmt.Fprintln(w, "Hello from Go on Workers")
        })
        workers.Serve(nil) // JS グルーが fetch を Go ハンドラへ橋渡し
    }
  2. WASI 経路 — Cloudflare が WASI の(実験的)対応を追加。Go 1.21+ の GOOS=wasip1 GOARCH=wasm や TinyGo の wasi ターゲットで、ファイル/標準入出力など WASI システムコールを使うコードを載せられる。

仕組み(なぜグルーが要るか)

fetch イベント(JS) → JS グルーが wasm を instantiate → export 関数を呼ぶ
            ↑ KV/R2/D1 などのバインディングも JS 経由で wasm に import

WASM 単体は外界と繋がれない(純粋な計算機械)。syumai/workers はこの JS↔wasm の橋渡しを隠蔽し、Go 側からは普通の HTTP サーバに見せている。

制約(理解して使う)

なぜやるか

Go のエコシステム・型安全・既存資産をエッジに持ち込める。ただし「ネイティブ Go が動く」のではなく「WASM + 制約環境(単一スレッド・JS 橋渡し・サイズ上限)で動かす」と理解するのが肝。エッジ/WASM ランドスケープの「複数言語をエッジへ」という流れの Go 版。

押さえどころ(カード化候補)

関連

Graph