Skip to content

Cloudflare Workers + Vite

You can build a full-stack application on Cloudflare Workers with Vite using the @cloudflare/vite-plugin. This setup gives you a fast Vite dev server, server-side rendering with Hono's JSX renderer, and client-side scripts bundled by Vite — all running on Cloudflare Workers.

This is the recommended way to start a new full-stack project on Cloudflare.

1. Setup

A starter for Cloudflare Workers with Vite is available. Start your project with the "create-hono" command. Select the cloudflare-workers+vite template for this example.

sh
npm create hono@latest my-app
sh
yarn create hono my-app
sh
pnpm create hono my-app
sh
bun create hono@latest my-app
sh
deno init --npm hono my-app

Move into my-app and install the dependencies.

sh
cd my-app
npm i
sh
cd my-app
yarn
sh
cd my-app
pnpm i
sh
cd my-app
bun i

Below is a basic directory structure.

text
./
├── package.json
├── public // Put your static files here.
├── src
│   ├── index.tsx // The entry point for server-side.
│   ├── renderer.tsx
│   └── style.css
├── tsconfig.json
├── vite.config.ts
└── wrangler.jsonc

The vite.config.ts combines the Cloudflare plugin with vite-ssr-components for SSR:

ts
import { cloudflare } from '@cloudflare/vite-plugin'
import { defineConfig } from 'vite'
import ssrPlugin from 'vite-ssr-components/plugin'

export default defineConfig({
  plugins: [cloudflare(), ssrPlugin()],
})

2. Hello World

Edit src/index.tsx like the following:

tsx
import { Hono } from 'hono'
import { renderer } from './renderer'

const app = new Hono()

app.use(renderer)

app.get('/', (c) => {
  return c.render(<h1>Hello, Cloudflare Workers!</h1>)
})

export default app

The renderer is defined in src/renderer.tsx using Hono's JSX renderer middleware together with vite-ssr-components, which wires up Vite's client and assets:

tsx
import { jsxRenderer } from 'hono/jsx-renderer'
import { Link, ViteClient } from 'vite-ssr-components/hono'

export const renderer = jsxRenderer(({ children }) => {
  return (
    <html>
      <head>
        <ViteClient />
        <Link href='/src/style.css' rel='stylesheet' />
      </head>
      <body>{children}</body>
    </html>
  )
})

3. Run

Run the development server locally. Then, access http://localhost:5173 in your web browser.

sh
npm run dev
sh
yarn dev
sh
pnpm dev
sh
bun run dev

4. Deploy

If you have a Cloudflare account, you can deploy to Cloudflare. The deploy script builds with Vite and then publishes with Wrangler.

sh
npm run deploy
sh
yarn deploy
sh
pnpm run deploy
sh
bun run deploy

Bindings

You can use Cloudflare Bindings like Variables, KV, D1, and others. Configure them in wrangler.jsonc. For example, to add a Variable named MY_NAME:

jsonc
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "my-app",
  "compatibility_date": "2025-08-03",
  "main": "./src/index.tsx",
  "vars": {
    "MY_NAME": "Hono",
  },
}

To generate the types for your Bindings, run the cf-typegen script:

sh
npm run cf-typegen
sh
yarn cf-typegen
sh
pnpm run cf-typegen
sh
bun run cf-typegen

This generates a CloudflareBindings interface. Pass it to Hono as generics:

ts
const app = new Hono<{ Bindings: CloudflareBindings }>()

Then access the Bindings via c.env:

tsx
app.get('/', (c) => {
  return c.render(<h1>Hello! {c.env.MY_NAME}</h1>)
})

Client-side

vite-ssr-components lets you load client-side scripts through Vite. Add a Script component pointing to your client entry point, and Vite handles bundling for both dev and production:

tsx
import { jsxRenderer } from 'hono/jsx-renderer'
import { Script, ViteClient } from 'vite-ssr-components/hono'

export const renderer = jsxRenderer(({ children }) => {
  return (
    <html>
      <head>
        <ViteClient />
        <Script src='/src/client.ts' />
      </head>
      <body>{children}</body>
    </html>
  )
})

For more details, see the @cloudflare/vite-plugin documentation and vite-ssr-components.

Released under the MIT License.