Skip to main content
package.json scripts:
vite preview serves the client build only. It is not a production Node server. If you deploy to Node, add the server.mjs below after vite build.

Cloudflare Workers

Follow Cloudflare Workers and Bindings. Short version:
wrangler.jsonc
Force the bundler target with betterRouter({ target: "cloudflare" }). Presence of wrangler.jsonc already selects Cloudflare.

Node

Add a small production server and "start": "node server.mjs" when you deploy to Node:
server.mjs
Load .env yourself in production (Docker, systemd, or node --env-file=.env). Vite will not inject it into dist/server. D1, R2 bindings, and Cloudflare Queues do not exist on Node. Pass process.env as env so getEnv() still sees your secrets.

Bun and Deno

The worker module is a fetch listener:
Deno is the same idea with Deno.serve and Deno.env.

What to verify after deploy

  • / returns HTML with #app and a script at /assets/client.js (path may be hashed depending on Vite)
  • /api/hello returns JSON
  • Bindings you declared in Wrangler are readable from getEnv() on a Worker request
SPA client URLs must be served by fetch (the Worker or Node Hono app), not only a CDN that 404s unknown paths. Cloudflare assets handles static files and falls through to the Worker for the rest.