Skip to content

Vite

Cloudflare.Website.Vite deploys any app that is pure Vite — a project whose entire build is vite build with plugins from your vite.config.ts. That covers a plain index.html, a React or Vue SPA, and full-stack SSR frameworks like TanStack Start or React Router. This page explains the resource itself; each supported framework has its own landing page that flows from here.

The minimal form takes no props at all:

const site = yield* Cloudflare.Website.Vite("Website");

Alchemy loads your project’s Vite install (resolved from rootDir’s package.json), appends the Cloudflare Vite plugin — Alchemy’s fork of @cloudflare/vite-plugin — to the plugins your vite.config.ts already declares, and runs builder.buildApp(). Client assets are uploaded as Worker static assets; if the build emits a server bundle (SSR), that bundle becomes the Worker entry — otherwise the Worker is assets-only. There is no main entrypoint, no build command, no output directory, and no wrangler.jsonc: an index.html next to your alchemy.run.ts (plus your vite.config.ts, if you have one) is enough.

Condensed from the provider, a deploy runs exactly this:

const vite = await loadVite(rootDir); // your project's own vite install
const builder = await vite.createBuilder({
root: rootDir,
define: getDefine(env), // VITE_-prefixed env, see Environment below
plugins: [cloudflare(pluginOptions), outputPlugin.plugin],
}, null);
await builder.buildApp();

A framework is supported if — and only if — a vite build of your vite.config.ts builds the whole app. Frameworks whose build is orchestrated by their own CLI (astro build, nuxi build) never enter this path, so they are not yet supported by this resource — see Astro and Nuxt for their current status and workarounds, or StaticSite as the general fallback for any build command that produces a directory of files.

ViteProps is WorkerProps minus the things the build now owns (main, the directory-shaped assets), plus Vite-specific options:

const site = yield* Cloudflare.Website.Vite("Website", {
rootDir: "./web",
compatibility: { flags: ["nodejs_compat"] },
assets: { runWorkerFirst: true },
});
  • rootDir — Vite’s project root, default process.cwd().
  • memo — narrows which files are hashed to decide whether a rebuild is needed (see Rebuilds and memo).
  • viteEnvironments — for frameworks that build more than one server environment (see Multiple server environments).
  • assets — a flat AssetsConfig for routing behavior: runWorkerFirst, htmlHandling, notFoundHandling, etc. The built asset directory is supplied by the build, so unlike a plain Worker there is no directory to configure.
  • Everything else is inherited from the Worker — domain, env, compatibility, crons, and so on. See Workers.

Like Worker, the resource also has a class form — useful when other resources bind to the site, or when you want to derive its env types:

export class Website extends Cloudflare.Website.Vite<Website>()("Website", {
compatibility: { flags: ["nodejs_compat"] },
}) {}

See TanStack Start for the class form in a real app.

env feeds your app through two distinct channels: build-time inlining into the client bundle, and runtime Worker bindings for server code.

Only VITE_-prefixed keys are inlined into the client bundle as import.meta.env.<KEY>, matching vite build’s default envPrefix semantics:

const web = yield* Cloudflare.Website.Vite("Website", {
env: {
VITE_API_URL: backend.url.as<string>(),
},
});

Output values like backend.url resolve at deploy time before the build runs, so the client reads a concrete import.meta.env.VITE_API_URL. Redacted values are unwrapped when VITE_-prefixed — the prefix means you are opting the value into the public bundle, so don’t prefix secrets with VITE_.

Non-VITE_ values become native Worker bindings, available to SSR code and typed via Cloudflare.InferEnv:

export class Website extends Cloudflare.Website.Vite<Website>()("Website", {
compatibility: { flags: ["nodejs_compat"] },
env: {
BUCKET: Bucket,
BACKEND: Backend,
},
}) {}
export type WebsiteEnv = Cloudflare.InferEnv<typeof Website>;

See TanStack Start for the full pattern of consuming these bindings from server routes.

viteEnvironments defaults to { entry: "ssr", children: [] }. Frameworks that emit several server environments — React Server Components split into rsc and ssr — declare which environment produces the Worker entry chunk and which are bundled alongside it:

const app = yield* Cloudflare.Website.Vite("ReactRouterRSC", {
compatibility: { flags: ["nodejs_compat"] },
viteEnvironments: { entry: "rsc", children: ["ssr"] },
});

The entry environment becomes the deployed Worker entry, children chunks are bundled alongside it, and the client environment is always deployed as static assets. See React Router for the worked example.

By default, every non-gitignored file under rootDir plus the nearest lockfile is content-hashed; if nothing changed, both the build and the deploy are skipped entirely. The hash is path-insensitive — relocating rootDir with identical sources is a no-op deploy. Narrow the scope with memo when the project contains large directories that don’t affect the build output:

const site = yield* Cloudflare.Website.Vite("Docs", {
memo: {
include: ["src/**", "index.html", "package.json"],
},
});
Terminal window
bun alchemy dev

alchemy dev boots Vite’s own dev server programmatically with the Cloudflare plugin attached — you get HMR on your application code while bindings point at the real cloud resources, so there is no emulation fidelity gap. By default the dev server picks an available port; set dev.port to keep the local URL stable across runs:

const web = yield* Cloudflare.Website.Vite("Website", {
dev: { port: 3000 },
});

Each supported framework has its own landing page building on this resource:

  • React SPA — single-page apps, from a bare index.html to the create-vite template.
  • TanStack Start — full-stack React and Solid with server routes and typed bindings.
  • React Router — including React Server Components via viteEnvironments.
  • Vue — Vue 3 SPAs.
  • SolidStart — SolidStart and hand-rolled SolidJS SSR.

Not yet supported by this resource: Astro and Nuxt — their builds are driven by their own CLIs, not vite build. Their pages document the current workarounds, generally deploying build output with StaticSite.