Edit

Cloudflare

We recommend using Photon for a seamless and full-fledged Cloudflare integration.

The entire documentation for using Cloudflare with Photon is contained on this page and vike-photon.

In development, your server code runs inside workerd (the runtime Cloudflare uses in production), so you're developing in an environment similar to production. This is a new Cloudflare feature that Photon fully supports.

Alternatively, for more control, you can manually integrate Cloudflare instead of using Photon.

Photon is currently in beta — you can use it in production, but expect breaking changes more frequently than usual.

You can use Cloudflare to deploy static websites as well as SSR.

If you pre-render partially, then your pre-rendered pages are statically deployed while your SSR pages are served dynamically.

Get started

New app

Use vike.dev/new to scaffold a new Vike app that uses Cloudflare with Photon.

Add to existing app

If you're using vike-server then migrate to vike-photon.

1. Install

npm i wrangler vike-photon @photonjs/cloudflare
// pages/+config.js
 
import vikePhoton from 'vike-photon/config'
 
export default {
  extends: [vikePhoton] 
}
// pages/+config.ts
 
import type { Config } from 'vike/types'
import vikePhoton from 'vike-photon/config'
 
export default {
  extends: [vikePhoton],
} satisfies Config

Photon automatically uses @photonjs/cloudflare if it's listed in your package.json dependencies. No additional steps are required.

2. Scripts

// package.json
 
{
  "scripts": {
    "dev": "vike dev",
    "preview": "vike build && vike preview",
    "deploy": "vike build && wrangler deploy"
  }
}

3. Wrangler config

// wrangler.jsonc
 
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "compatibility_date": "2025-08-06",
  "name": "my-vike-cloudflare-app",
  "main": "virtual:photon:cloudflare:server-entry",
  // Only required if your app (or one of your libraries) uses a Node.js API
  "compatibility_flags": ["nodejs_compat"]
}
# .gitignore
 
.wrangler/

4. Server (optional)

Photon includes a built-in server that supports basic features like SSR. If you need additional server functionalities (e.g. file uploads or API routes), see vike-photon > Server.

Cloudflare APIs

To access Cloudflare's APIs (such as D1 and KV), use Cloudflare's bindings, which are available via the env object that you can import from cloudflare:workers.

// Environment: server
 
import { env } from 'cloudflare:workers'
// Key-value store
env.KV.get('my-key')
// Environment Variable
env.LOG_LEVEL
// ...

Example of using Cloudflare D1:

npm create vike@latest --- --react --hono --drizzle --cloudflare

Or go to vike.dev/new and select Cloudflare with an ORM.

To make environment variables available on the client-side, you can use +onCreateGlobalContext.server.js with a custom globalContext property and passToClient.

// pages/+onCreateGlobalContext.server.js
// Environment: server
 
export { onCreateGlobalContext }
 
import { env } from 'cloudflare:workers'
 
async function onCreateGlobalContext(globalContext) {
  // Making the environment variable LOG_LEVEL available on the client-side
  globalContext.logLevel = env.LOG_LEVEL || 'info'
}
// pages/+onCreateGlobalContext.server.ts
// Environment: server
 
export { onCreateGlobalContext }
 
import { env } from 'cloudflare:workers'
import type { GlobalContextServer } from 'vike/types'
 
async function onCreateGlobalContext(globalContext: GlobalContextServer) {
  // Making the environment variable LOG_LEVEL available on the client-side
  globalContext.logLevel = env.LOG_LEVEL || 'info'
}
 
declare global {
  namespace Vike {
    interface GlobalContext {
      logLevel: string
    }
  }
}
// pages/+config.js
 
export default {
  passToClient: ['logLevel']
}
// pages/+config.ts
 
import type { Config } from 'vike/types'
 
export default {
  passToClient: ['logLevel']
} satisfies Config
// anywhere.js
// Environment: server and/or client
 
import { getGlobalContext } from 'vike'
 
const globalContext = getGlobalContext()
// Available anywhere
console.log(globalContext.logLevel)
// anywhere.ts
// Environment: server and/or client
 
import { getGlobalContext } from 'vike'
 
const globalContext = getGlobalContext()
// Available anywhere
console.log(globalContext.logLevel)

TypeScript

If you use TypeScript, (re-)run wrangler types after changing your Cloudflare configuration to generate/update the worker-configuration.d.ts file.

npx wrangler types

Then commit it:

git commit -am "update cloudflare types"

Make sure TypeScript loads it:

// tsconfig.json
 
{
  "compilerOptions": {
    "types": ["./worker-configuration.d.ts"],
 }
}

See also: Cloudflare Workers > TypeScript

Extend 3MB limit

By default the bundle size of your worker cannot exceed 3MB, but you can request sizes of up to 100MB and beyond.

Manual integration

Instead of using vike-photon, you can manually integrate your app with Cloudflare yourself.

Cloudflare Pages

For a manual integration, we generally recommend using:

Examples:

Workers

You can also directly use Cloudflare Workers instead of using Cloudflare Pages.

Cloudflare Workers requires your entire worker code to be bundled into a single file — you can use Wrangler to achieve that (it uses esbuild under the hood).

Cloudflare uses the term "worker code" to denote server code that is run on its edge infrastructure.

Examples:

Development

For a significantly faster development experience we recommend, whenever possible, using Vite's development server (or a server such as Express.js or Hono) instead of Wrangler.

In other words:

  • Skip wrangler / Cloudflare Workers altogether while developing your app.
  • Use wrangler dev to preview your worker.
  • Use wrangler publish to deploy your worker to Cloudflare Workers.

Examples:

Universal fetch()

When using Node.js(/Bun/Deno) for development and Cloudflare Workers for production, you may need a fetch() function that works in both environments.

You can define a fetch function at pageContext.fetch that works in all environments. The trick is to add a different fetch() implementation to pageContextInit at renderPage(pageContextInit).

Example: /examples/cloudflare-workers-react-full#universal-fetch.

Libraries such as node-fetch or cross-fetch typically don't work with Cloudflare Workers.

See also