本文へ移動

Workflows を binding なしで ctx.exports から呼ぶ、同名なら既存インスタンスを共有

Cloudflare Workflows を ctx.exports で呼ぶ条件と、既存インスタンスを共有する name の照合先を整理する。ローカル開発の最低バージョンと Vitest のテスト専用 binding も確認する。

Cloudflare Workflows を、それを定義している Worker 自身から呼ぶだけなら、workflows binding はもう要らない。2026年9月27日付の Cloudflare changelog によると、Wrangler 設定の exports フィールドで宣言した Workflow は ctx.exports 経由で呼べる。binding から export に移しても、binding と export が同じ名前ならインスタンスは共有されるので、既存のインスタンスは失われないと明記されている。

引っかかりうるのは二か所だ。ローカル開発ツールのバージョンが下限に届いていない場合と、Vitest で introspectWorkflow() や introspectWorkflowInstance() を使っているテストである。後者はいまも binding を前提にしている。

呼び出しは class 名がキーになる

ctx.exports の下には Workflow が class 名をキーにして並ぶ。API は Workflow binding と同じとされているので、binding 名で呼んでいた箇所を ctx.exports.<クラス名> に置き換える形になる。changelog に載っている TypeScript の例は次のとおりだ。

export default {
  async fetch(request, env, ctx): Promise<Response> {
    const instance = await ctx.exports.MyWorkflow.create({
      params: { name: "World" },
    });
    return Response.json({ id: instance.id });
  },
} satisfies ExportedHandler<Env>;

ctx は fetch の第 3 引数で、env は使っていない。binding 名と class 名を別々に管理していたプロジェクトでは、呼び出し側のコードが参照する名前が変わる点に注意したい。

対象は「その Workflow を定義している Worker から呼ぶ場合」に限られる。別の Worker から Workflow を呼ぶケースについて、この changelog は何も述べていない。そちらは従来どおり binding で呼ぶ前提で考えておくのが無難だ。

binding から export へ移すときに残るもの

インスタンスを共有する条件は、Workflow 自体の名前が同じことだ。Cloudflare のWorkers API の設定例では、従来の workflows 配列にある name と、新しい exports.<クラス名>.name に同じ値を指定する。呼び出しに使う binding 名や ctx.exports のクラス名とは区別して照合したい。

移行の順序(binding を先に消すか、しばらく両方を並べるか)も書かれていない。両者がインスタンスを共有するという記述からは、並存させても同じインスタンス群を見ると読める。ただしこれは推測で、公式に順序が示されているわけではない。

Workflows のインスタンス操作まわりでは、直近ではイベント購読の API も入っている(.subscribe() の挙動)。インスタンスを外から追っている仕組みがあるなら、移行後も同じ ID で追えるかを合わせて見ておくと安全だ。

ローカル開発のバージョン下限

wrangler dev、Cloudflare Vite plugin、Workers Vitest integration は、ctx.exports 上の Workflow をローカルで動かせる。そのための下限は次のとおり。

使っているツール必要なバージョン
Wrangler(wrangler dev)4.142.0 以上
@cloudflare/vite-plugin1.61.0 以上
@cloudflare/vitest-plugin1.3.0 以上

出典:Cloudflare Changelog「Call Workflows declared in exports through ctx.exports」(2026年9月27日)

changelog はこの 3 つを「または」でつないでいるので、自分の開発フローで使っているツールが下限を満たしていればよい、と読むのが自然だ。下限未満のツールで ctx.exports の Workflow を呼んだときにどう失敗するかは書かれていない。CI でローカル実行系を固定しているなら、先にバージョンを上げてから呼び出しを書き換えるほうが原因の切り分けが楽になる。

Vitest の introspect は binding を探しにいく

Vitest で Workflow の実行を検査する introspectWorkflow() と introspectWorkflowInstance() は、いまも Workflow binding を必要とする。exports で宣言した Workflow を検査したいなら、テスト専用の binding を追加するよう changelog は案内している。

つまり、本番コードから binding を消しても、テストで introspect を使う限り binding の定義はテスト側に残る。テスト専用 binding を設定のどこにどう書くか(本番設定と分けるのか、同じ設定に置くのか)は changelog には載っていない。

移すかどうかの判断

binding が使えなくなるとは書かれていないので、今日やらなければならない作業はない。移す価値があるのは、自分の Worker の中だけで Workflow を呼んでいて、binding の定義を減らしたいチームだ。その場合の確認は 3 点に絞れる。

  • workflows[].name と exports.<クラス名>.name がそろっているか(インスタンス共有の条件)
  • ローカル開発ツールが上の表の下限を満たしているか
  • Vitest で introspect を使っているなら、テスト専用 binding を用意したか

introspect を多用しているテストスイートでは、binding が設定から完全には消えない。その手間と引き換えに移すかどうかを決めればよい。

出典 種別について