Skip to content

docs(cloudflare): fix env bindings access pattern for Nitro v3 (breaking change)#4064

Open
ruan-cat wants to merge 2 commits intonitrojs:mainfrom
ruan-cat:fix-doc/cloudflare-env-v3
Open

docs(cloudflare): fix env bindings access pattern for Nitro v3 (breaking change)#4064
ruan-cat wants to merge 2 commits intonitrojs:mainfrom
ruan-cat:fix-doc/cloudflare-env-v3

Conversation

@ruan-cat
Copy link

Note: This pull request was authored with AI assistance (Claude Sonnet 4.6). The documentation changes, code analysis, and technical explanations were generated and reviewed by an AI agent. The underlying issue was discovered and reported by a human developer.


Summary

This PR fixes outdated documentation for accessing Cloudflare Worker environment variables and bindings in Nitro v3. The existing docs still show the Nitro v2 pattern (event.context.cloudflare.env), which does not work in production with Nitro v3. This has been a source of confusion for developers migrating from v2 to v3.

Problem

The current documentation in docs/2.deploy/20.providers/cloudflare.md shows:

defineHandler(async (event) => {
  const { cloudflare } = event.context
  const stmt = await cloudflare.env.MY_D1.prepare('SELECT id FROM table')
  const { results } = await stmt.all()
})

This pattern (event.context.cloudflare.env) was correct in Nitro v2 but fails silently in Nitro v3 production deploymentsevent.context.cloudflare is undefined at runtime, so accessing .env on it throws or returns nothing.

Additionally, the migration guide (docs/1.docs/99.migration.md) has no mention of this breaking change, leaving developers without guidance when upgrading.

Root Cause

In Nitro v3, the underlying server layer switched from H3/unenv to srvx. As a result, the Cloudflare preset's production runtime entry now attaches the Cloudflare context to the request's runtime object rather than the event context.

The relevant code is in src/presets/cloudflare/runtime/_module-handler.ts:

// Lines 113-124
export function augmentReq(
  cfReq: Request | CF.Request,
  ctx: NonNullable<ServerRuntimeContext["cloudflare"]>
) {
  const req = cfReq as ServerRequest;
  req.runtime ??= { name: "cloudflare" };
  req.runtime.cloudflare = { ...req.runtime.cloudflare, ...ctx };  // <-- env lives here
  req.waitUntil = ctx.context?.waitUntil.bind(ctx.context);
}

The augmentReq() function is called in the production fetch handler:

async fetch(request, env, context) {
  (globalThis as any).__env__ = env;
  augmentReq(request as any, { env: env as any, context });  // attaches to req.runtime
  // ...
}

This means in Nitro v3, the correct path to access Cloudflare bindings is:

const { env } = event.req.runtime.cloudflare

Why does it seem to work in local dev?

The dev plugin (src/presets/cloudflare/runtime/plugin.dev.ts) still populates event.req.context.cloudflare for local development via the Wrangler proxy. This creates a confusing discrepancy: the old pattern works locally but fails in production.

Evidence

Debug Endpoint

A diagnostic API endpoint was written to probe all possible paths for Cloudflare env access in Nitro v3:

Source: server/api/debug-env.get.ts

Key probe from that file:

// @ts-ignore — event.req.runtime is the Nitro v3 Cloudflare runtime injection
const reqRuntime = (event.req as any)?.runtime;
if (reqRuntime !== undefined) {
  const cfRuntime = reqRuntime?.cloudflare;
  if (cfRuntime !== undefined) {
    const cfRuntimeEnv = cfRuntime?.env;
    // env keys are accessible here ✓
  }
}

Live Reproducible Demo

The endpoint is deployed to Cloudflare Workers using Nitro v3:

URL: https://01s-11.ruan-cat.com/api/debug-env

This live endpoint confirms that:

  • req.runtime.cloudflare.env contains the environment variables and bindings ✓
  • event.context.cloudflare is undefined in production ✗

Changes

This PR modifies documentation only — no source code changes.

docs/2.deploy/20.providers/cloudflare.md

  • Updated the "Direct access to Cloudflare bindings" section to show the correct Nitro v3 pattern (event.req.runtime.cloudflare.env)
  • Added a ::warning callout explaining the breaking change from v2

docs/1.docs/99.migration.md

  • Added a new "Cloudflare Bindings Access" section documenting the breaking change
  • Includes a diff migration example showing the old v2 pattern vs. the new v3 pattern
  • Includes a warning about the local dev vs. production discrepancy

Testing

The fix can be verified by deploying a Nitro v3 app to Cloudflare Workers and confirming that event.req.runtime.cloudflare.env returns the expected bindings. The live demo at https://01s-11.ruan-cat.com/api/debug-env serves as a reproducible test case.

Update cloudflare.md to show the correct v3 pattern (event.req.runtime.cloudflare.env)
and add a breaking change warning. Add migration section to 99.migration.md.
@ruan-cat ruan-cat requested a review from pi0 as a code owner February 28, 2026 14:29
@vercel
Copy link

vercel bot commented Feb 28, 2026

@ruan-cat is attempting to deploy a commit to the Nitro Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link

coderabbitai bot commented Feb 28, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2b1d6a0b-83a6-4cb6-bbc9-3a6eb90f11d7

📥 Commits

Reviewing files that changed from the base of the PR and between 72c6b8f and ddb3751.

📒 Files selected for processing (1)
  • docs/1.docs/99.migration.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/1.docs/99.migration.md

📝 Walkthrough

Walkthrough

Adds documentation updates instructing migration from event.context.cloudflare.env to event.req.runtime.cloudflare.env with revised code examples and a Nitro v3 breaking-change warning across migration and Cloudflare provider docs. (≈34 words)

Changes

Cohort / File(s) Summary
Migration Documentation
docs/1.docs/99.migration.md
Adds "Cloudflare Bindings Access" migration section showing code diff from event.context.cloudflare.env to event.req.runtime.cloudflare.env; includes a small typographic correction in Node.js recommendation.
Cloudflare Provider Documentation
docs/2.deploy/20.providers/cloudflare.md
Replaces D1/Bindings example to use event.req.runtime.cloudflare.env; adds a Nitro v3 breaking-change warning clarifying old pattern may be undefined in production.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The PR title follows conventional commits format with 'docs' scope and clearly describes the documentation fix for the Cloudflare env bindings access pattern in Nitro v3.
Description check ✅ Passed The PR description is comprehensive and directly related to the changeset, providing detailed context about the breaking change, root cause analysis, evidence, and the specific documentation updates made.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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 and usage tips.

@ruan-cat
Copy link
Author

ruan-cat commented Feb 28, 2026

@pi0 Can you check and review it?

I was discovered within the nitro v3 version, with the aid of AI event. The event.req.runtime.cloudflare.env access to obtain cloudflare worker set environment variables. This helped me deploy a working vue project on cloudflare, successfully load environment variables from the neon database, and make valid http network requests.

I hope to merge into the main branch soon. This change is documentation only and adds more detail to the already patchy nitro v3 documentation.

@RihanArfan RihanArfan self-requested a review March 4, 2026 13:48
Copy link
Member

@RihanArfan RihanArfan left a comment

Choose a reason for hiding this comment

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

Great docs fix — the v2 → v3 binding path change definitely needed documenting. I've been looking at this from the code side too, and there's a related issue: the Wrangler dev proxy plugin (src/presets/cloudflare/runtime/plugin.dev.ts) still sets bindings on the old event.req.context.cloudflare path instead of event.req.runtime.cloudflare. This means the old pattern appears to work in local dev (which is why the warnings below mention it), but fails in production.

The fix is straightforward — update the dev plugin to match the production augmentReq behavior from _module-handler.ts:

nitroApp.hooks.hook("request", async (event) => {
    (event.req as any).cf = proxy.cf;
    event.req.runtime ??= { name: "cloudflare" };
    event.req.runtime.cloudflare = {
      ...event.req.runtime.cloudflare,
      env: proxy.env,
      context: proxy.ctx,
    };
    event.req.waitUntil = proxy.ctx.waitUntil.bind(proxy.ctx);
});

With that fix applied, the "may still appear to work in local dev" caveats in the docs become inaccurate — hence the inline suggestions below to simplify the warning text.

I've verified this works end-to-end: set up a playground with the cloudflare-module preset, a wrangler.jsonc with a KV binding, and a test route using event.req.runtime.cloudflare.env — KV read/write works correctly through the dev emulation.

Comment on lines +294 to +296

::warning
**Nitro v3 Breaking Change:** The `event.context.cloudflare.env` pattern from Nitro v2 no longer works in production. Use `event.req.runtime.cloudflare.env` instead. The old pattern may still appear to work in local dev (via the Wrangler proxy plugin) but will be `undefined` in production deployments.
Copy link
Member

@RihanArfan RihanArfan Mar 4, 2026

Choose a reason for hiding this comment

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

Same here — with the dev plugin fix, the local dev caveat no longer applies. Can simplify to:

Suggested change
::warning
**Nitro v3 Breaking Change:** The `event.context.cloudflare.env` pattern from Nitro v2 no longer works in production. Use `event.req.runtime.cloudflare.env` instead. The old pattern may still appear to work in local dev (via the Wrangler proxy plugin) but will be `undefined` in production deployments.
**Nitro v3 Breaking Change:** The `event.context.cloudflare.env` pattern from Nitro v2 has been changed to `event.req.runtime.cloudflare.env` in Nitro v3.
::

Co-authored-by: Rihan Arfan <me@file.properties>
@ruan-cat
Copy link
Author

ruan-cat commented Mar 4, 2026

Thanks for the review and the detailed explanation! I have applied your suggestion. (I'm new to this process, but the 'Commit suggestion' feature is really convenient!)

defineHandler(async (event) => {
const { cloudflare } = event.context
const stmt = await cloudflare.env.MY_D1.prepare('SELECT id FROM table')
// Nitro v3: access Cloudflare bindings via event.req.runtime.cloudflare.env
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we need the v3 code comment since these docs are for v3 rather than the migration guide.

@RihanArfan
Copy link
Member

Thank you for your changes @ruan-cat.

Please could you update the wrangler dev plugin in src/presets/cloudflare/runtime/plugin.dev.ts with the code from my review comment? If you enable edits from maintainers, I'm happy to make the changes for you :)

@ruan-cat
Copy link
Author

ruan-cat commented Mar 6, 2026

Thank you for your changes @ruan-cat.感谢您的修改。

Please could you update the wrangler dev plugin in src/presets/cloudflare/runtime/plugin.dev.ts with the code from my review comment? If you enable edits from maintainers, I'm happy to make the changes for you :)请问您能否用我评论中的代码更新 src/presets/cloudflare/runtime/plugin.dev.ts 版本的 Wrangler 开发插件?如果您允许维护者编辑,我很乐意为您进行修改 :)

I have enabled allow maintainers to edit. You can start editing.

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.

2 participants