{
  "slug": "wrangler-local-development-supports-workflows-in-ctx-exports-f77762c0df2d",
  "title": "wrangler local development supports Workflows in ctx.exports",
  "tools": [
    "wrangler"
  ],
  "tags": [
    "agent"
  ],
  "introduced_at": "2026-09-27T14:11:56.000Z",
  "announced_at": "2026-09-27T14:11:56.000Z",
  "effective_at": null,
  "date_basis": "source-publication",
  "status": "unknown",
  "how": {
    "incantation": "When a Worker declares a Workflow in `exports`, create it locally with `ctx.exports.<ClassName>.create({ params })`; use `wrangler workflows` with `--local` to trigger or inspect its instances. In Vitest, introspect through a test-only Workflow binding, which also captures instances created via `ctx.exports`.",
    "examples": [
      "const instance = await ctx.exports.MyWorkflow.create({ params: { name: \"World\" } });",
      "npx wrangler workflows trigger <WORKFLOW_NAME> '{\"name\":\"World\"}' --local\nnpx wrangler workflows instances describe <WORKFLOW_NAME> <INSTANCE_ID> --local",
      "cloudflareTest({ wrangler: { configPath: \"./wrangler.jsonc\" }, miniflare: { workflows: { MY_WORKFLOW: { name: \"my-workflow\", className: \"MyWorkflow\" } } } })\n\nawait using introspector = await introspectWorkflow(env.MY_WORKFLOW);\nawait exports.default.fetch(\"https://example.com/\");\nconst instances = await introspector.get();"
    ],
    "gotchas": [
      "Version: 4.142.0",
      "ctx.exports.MyWorkflow (required): Use the Workflow class name as the key to reach the exported Workflow API.",
      "params: Object passed as the Workflow instance input; example uses `{ name: \"World\" }`.",
      "<WORKFLOW_NAME> (required): Workflow name used by Wrangler commands.",
      "[PARAMS]: JSON string passed as the Workflow instance parameters.",
      "--local: Target the Workflow in a local `wrangler dev` session.",
      "--port: Select the local dev session port; defaults to `8787`.",
      "MY_WORKFLOW test binding (required): Vitest introspection requires a Workflow binding; configure `name` and `className` under `miniflare.workflows`.",
      "Prerequisite: For local exported Workflows, use Wrangler 4.142.0 or later, `@cloudflare/vite-plugin` 1.61.0 or later, or `@cloudflare/vitest-plugin` 1.3.0 or later, as appropriate.",
      "Prerequisite: Run a `wrangler dev` session before using `wrangler workflows ... --local`.",
      "Prerequisite: Vitest helpers from `cloudflare:test` and `cloudflare:workers` must be imported from test files running in the Workers runtime.",
      "`ctx.exports` and `workflows` bindings with the same Workflow `name` share their instances, including instances created before the Workflow was declared in `exports`.",
      "Two Workers can't export the same Workflow name.",
      "A binding to an exported Workflow must refer to the Worker and class that export it.",
      "`getPlatformProxy()` ignores Workflows declared in `exports`, since it doesn't run the Worker's code.",
      "In the Vitest plugin, `introspectWorkflow()` and `introspectWorkflowInstance()` still need a Workflow binding.",
      "A `workflows` binding whose `script_name` is the Worker's own name resolves to the Worker itself again."
    ]
  },
  "why_it_matters": "Create and introspect a Workflow declared in a Worker’s `exports` while developing or testing the Worker locally.",
  "before": "Before this change, a Worker could define a Workflow through a `workflows` binding; calling an exported Workflow through `ctx.exports` was not available.",
  "sources": [
    "https://github.com/cloudflare/workers-sdk/releases/tag/wrangler%404.142.0",
    "https://developers.cloudflare.com/changelog/post/2026-09-27-workflow-ctx-exports/",
    "https://developers.cloudflare.com/workflows/build/local-development/",
    "https://developers.cloudflare.com/workers/testing/vitest-integration/test-apis/",
    "https://developers.cloudflare.com/workers/wrangler/commands/workflows/",
    "https://developers.cloudflare.com/changelog/product/workflows/"
  ],
  "rank": 0.97038,
  "judge": {
    "publish": true,
    "judge_model": "codex-cli/gpt-6-luna+typesafe/jev-1.13.0",
    "prompt_version": "extract-v7+enrich-v1+judge-v2x3+jev-publish-v1"
  },
  "review_state": "approved",
  "provenance": {
    "run_id": "gap-20261007",
    "verdict_id": "gap-20261007:gap-20261007-ab2af6ce95cb5b9c-0:gate",
    "evidence_hash": "11d78c613782a8dd8634c1bdca4468cbfdd7e2c82929d5df824b8f9eb6ecd607"
  },
  "review": {
    "draft_hash": "7919c7dde2e9cf5f0ca45d7b25bc559f08e32061a8ce7cf1f199fed83df3d112",
    "reviewer": "publication-gate",
    "reviewed_at": "2026-10-07T00:00:00.000Z",
    "decision": "gap-20261007:gate",
    "reason": "3 of 3 judge runs approved with p_yes >= 0.9 (mean 0.97 >= 0.9; 2 needed) and Jev gave 0.76 (>= 0.6 needed)."
  }
}
