Skip to content

fix(deploy): keep local .env values out of native framework Worker bundles - #732

Merged
cpojer merged 1 commit into
voidzero-dev:mainfrom
morinokami:fix/native-deploy-dotenv
Nov 6, 2026
Merged

cpojer merged 1 commit into
voidzero-dev:mainfrom
morinokami:fix/native-deploy-dotenv

Conversation

@morinokami

Copy link
Copy Markdown
Contributor

In a SvelteKit app on D1 with void installed from npm, void deploy --platform cloudflare puts the VITE_* values from the local .env into the uploaded Worker:

# .env
VITE_API_ORIGIN=http://localhost:8787
VITE_LOCAL_NOTE=only-on-my-laptop
// uploaded Worker (minified)
function m() {
  return Object.fromEntries(Object.entries({
    BASE_URL: "/", DEV: !1, MODE: "production", PROD: !0, SSR: !1,
    VITE_API_ORIGIN: "http://localhost:8787",
    VITE_LOCAL_NOTE: "only-on-my-laptop"
  }).filter(([e]) => e.startsWith("VITE_")));
}

With VITE_API_ORIGIN: url().default('https://api.example.com') in env.ts and no value in the build shell, the deployed Worker answers env.VITE_API_ORIGIN with http://localhost:8787, while the browser bundle has https://api.example.com. VITE_LOCAL_NOTE is not declared in env.ts and is readable too. The docs say builds ignore client values from .env.

Void's env plugin removes .env client values during Kit's build, but Kit's server build leaves an installed void/env as an import, so that module is not compiled there. Before the upload, prepareBundledBuildOutput bundles the adapter's Worker once more with Vite, with the project root as root and no envDir. Vite reads .env there and replaces import.meta.env in void/env with its values. Managed deploys bundle the same entry from .void/bundle, which has no .env.

Fix

The bundle sets envDir: false. Vite reads no env files there; values from the build shell still reach import.meta.env.

Tests

packages/void/test/unit/cf-build-output.test.ts bundles a framework Worker that imports a package reading import.meta.env as a whole, with VITE_ORIGIN in .env and VITE_SHELL_ORIGIN in the environment. The bundle contains the shell value and not the .env value. Without this fix, it contains both.

The SvelteKit playground does not show the problem: it links void from the workspace, so Kit bundles it in its own build and the second bundle finds no import.meta.env to replace.

Verification

  • vp test run: 781 files pass, 1 skipped (16,159 tests pass, 29 skipped).
  • vp run check: 33/33 pass.
  • By hand on a copy of the SvelteKit playground, with void copied into node_modules as a real directory: build, then prepareCfFrameworkBuildOutput and bundleEntry, each run in Miniflare. Without this fix, the native Worker returns the .env values from an API route and renders http://localhost:8787 in a page. With it, the native and managed Workers return the same values: none without a build-shell value, and the build-shell value when VITE_API_ORIGIN is set.
  • Not run: void deploy against Cloudflare, and Nuxt, Analog and Astro, which go through the same bundle.

Related: #729 keeps local values out of Astro's Worker through a different path (Astro's env plugin). The two changes touch different files and don't depend on each other.

🤖 Generated with Claude Code

…ndles

`void deploy --platform cloudflare` bundles a framework's Worker output
with Vite once more before uploading it. That build used the project
root as its env directory, so Vite read the local `.env` and put every
`VITE_*` value from it into `import.meta.env`, including keys that
`env.ts` does not declare.

A SvelteKit D1 app keeps an installed `void/env` as an import in its
server output, so this build is where that module's `import.meta.env`
is replaced. The uploaded Worker then returned the local `.env` value
for `env.VITE_*` keys that the build shell does not set, while the
browser bundle used the schema default. Managed deploys bundle from
`.void/bundle` and were not affected.

The bundle now sets `envDir: false`, as documented: builds ignore client
values from `.env`. Shell values still apply.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cpojer
cpojer merged commit 38f2e23 into voidzero-dev:main Nov 6, 2026
2 checks passed
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