Skip to content

presets(cloudflare): support durable objects, workflows and bindings in local dev - #4341

Open
zsilbi wants to merge 6 commits into
nitrojs:mainfrom
zsilbi:feat/cf-dev-bindings
Open

presets(cloudflare): support durable objects, workflows and bindings in local dev#4341
zsilbi wants to merge 6 commits into
nitrojs:mainfrom
zsilbi:feat/cf-dev-bindings

Conversation

@zsilbi

@zsilbi zsilbi commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #4338 — makes durable object and workflows usable in dev (miniflare runner).

🔗 Linked issue

#4339

❓ Type of change

  • 👌 Enhancement (improving an existing functionality like performance)

📚 Description

Compose a dev worker entry that statically re-exports binding-referenced classes from exports.cloudflare.ts (bundled with rolldown) and pass them to env-runner via exports — workerd requires them as static exports, while the app keeps loading through the Vite module runner (HMR intact, DO class changes need a restart - documented).

Forward env/ctx to the app in the dev worker, same as the prod module handler (globalThis.__env__ + req.runtime.cloudflare).

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

@zsilbi
zsilbi requested a review from pi0 as a code owner June 11, 2026 21:38
@vercel

vercel Bot commented Jun 11, 2026

Copy link
Copy Markdown

@zsilbi is attempting to deploy a commit to the Nitro Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 64b20275-2b78-45e1-8847-941d7bdd744b

📥 Commits

Reviewing files that changed from the base of the PR and between 357dd96 and 078fa53.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (1)
  • examples/cloudflare-durable/package.json

📝 Walkthrough

Walkthrough

This PR adds Cloudflare Durable Objects and Workflows support to Nitro through dev-worker composition, Cloudflare runtime binding propagation, documentation, an end-to-end example, and Vite integration tests.

Changes

Cloudflare Durable Objects Integration

Layer / File(s) Summary
Documentation and user example
docs/2.deploy/20.providers/cloudflare.md, examples/cloudflare-durable/*
Documents Durable Object exports, bindings, migrations, runtime access, and restart behavior; adds a working counter example and deployment configuration.
Cloudflare export utilities
src/presets/cloudflare/entry-exports.ts, src/presets/cloudflare/utils.ts
Exports the helpers used to resolve Cloudflare exports and read Wrangler configuration.
Dev-worker composition
src/presets/cloudflare/dev.ts
Discovers bound Durable Object and Workflow classes, bundles exports, and generates a wrapper that forwards worker lifecycle handlers.
Miniflare and runtime integration
src/build/vite/env.ts, src/runtime/internal/vite/dev-worker.mjs
Connects the composed worker to Miniflare and propagates Cloudflare environment and execution context into requests.
Fixture and integration coverage
test/examples.test.ts, test/vite/cloudflare-do-fixture/*, test/vite/cloudflare-do.test.ts
Adds Durable Object and Workflow fixtures and verifies counter persistence, environment exposure, and workflow bindings in Vite dev mode.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows conventional commits format with a type, scope, and concise subject matching the change.
Description check ✅ Passed The description clearly describes the durable objects, workflows, dev worker, and docs changes in this PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@socket-security

socket-security Bot commented Jun 11, 2026

Copy link
Copy Markdown

No dependency changes detected. Learn more about Socket for GitHub.

👍 No dependency changes detected in pull request

@pkg-pr-new

pkg-pr-new Bot commented Jun 11, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/nitro@4341

commit: 078fa53

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/cloudflare-durable/routes/counter.ts`:
- Around line 4-8: The code assumes event.req.runtime?.cloudflare?.env exists
and directly casts it, which will throw a TypeError if missing; update the
handler (defineHandler) to validate that event.req.runtime?.cloudflare?.env is
defined and that env.COUNTER exists before calling
env.COUNTER.getByName("global"), and throw a clear, descriptive error (e.g.,
"Missing Cloudflare Durable Object binding: COUNTER") so callers get an
actionable message instead of a runtime TypeError; reference the env variable
and the COUNTER DurableObjectNamespace/CounterDO binding when adding the checks.

In `@src/presets/cloudflare/dev.ts`:
- Around line 149-153: IPC can call loadDevWorker() before
globalThis.__ENV_RUNNER_UNSAFE_EVAL__ is set, so guard and lazily initialize
that binding instead of dereferencing it; create a small helper (e.g.,
ensureUnsafeEval or createUnsafeEvalBinder) that if
globalThis.__ENV_RUNNER_UNSAFE_EVAL__ is undefined will initialize and assign a
safe fallback object exposing newAsyncFunction (built via the Function
constructor to return import(id) so it behaves like the real binder), then use
that helper when computing devWorkerPromise and in the other block (the similar
166-173 code) so loadDevWorker() never calls undefined.newAsyncFunction;
reference globalThis.__ENV_RUNNER_UNSAFE_EVAL__, devWorkerPromise,
loadDevWorker, newAsyncFunction, devWorkerId, and the ipc.onOpen / ipc.onMessage
pre-load paths when locating where to add the helper and replace direct
dereferences.
- Around line 152-154: The memoized devWorkerPromise (devWorkerPromise) is set
with ??= which leaves a permanently rejected promise on transient import
failures; update the promise chain returned by
newAsyncFunction(...)(devWorkerId) to attach a .catch handler that clears
devWorkerPromise (set it to undefined/null) before rethrowing the error so
subsequent attempts will retry, while keeping the successful .then branch that
sets devWorker; reference devWorkerPromise, devWorker, devWorkerId and the
newAsyncFunction(...).then(...) chain when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c8e33f58-1f23-4169-8454-e9ebef5545cd

📥 Commits

Reviewing files that changed from the base of the PR and between 7765bcb and b9506c6.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (23)
  • docs/2.deploy/20.providers/cloudflare.md
  • examples/cloudflare-durable/README.md
  • examples/cloudflare-durable/exports.cloudflare.ts
  • examples/cloudflare-durable/index.html
  • examples/cloudflare-durable/nitro.config.ts
  • examples/cloudflare-durable/package.json
  • examples/cloudflare-durable/routes/counter.ts
  • examples/cloudflare-durable/server/durable/counter.ts
  • examples/cloudflare-durable/tsconfig.json
  • examples/cloudflare-durable/vite.config.ts
  • examples/cloudflare-durable/wrangler.jsonc
  • src/build/vite/env.ts
  • src/presets/cloudflare/dev.ts
  • src/presets/cloudflare/entry-exports.ts
  • src/presets/cloudflare/utils.ts
  • src/runtime/internal/vite/dev-worker.mjs
  • test/examples.test.ts
  • test/vite/cloudflare-do-fixture/durable/counter.ts
  • test/vite/cloudflare-do-fixture/durable/entrypoint.ts
  • test/vite/cloudflare-do-fixture/exports.cloudflare.ts
  • test/vite/cloudflare-do-fixture/routes/counter.ts
  • test/vite/cloudflare-do-fixture/vite.config.ts
  • test/vite/cloudflare-do.test.ts

Comment thread examples/cloudflare-durable/routes/counter.ts
Comment thread src/presets/cloudflare/dev.ts
Comment thread src/presets/cloudflare/dev.ts
@zsilbi
zsilbi force-pushed the feat/cf-dev-bindings branch from d4b7ccd to 12cf095 Compare July 3, 2026 17:43
@zsilbi
zsilbi force-pushed the feat/cf-dev-bindings branch from c0bcf7a to 357dd96 Compare July 27, 2026 23:10
@zsilbi
zsilbi force-pushed the feat/cf-dev-bindings branch from 357dd96 to 078fa53 Compare July 27, 2026 23:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant