Skip to main content
The @cloudflare/vite-plugin-cloudflare package provides a Vite plugin for developing Cloudflare Workers and Pages applications with Vite’s development server and build tooling.

Installation

npm install -D @cloudflare/vite-plugin-cloudflare

Basic Usage

// vite.config.ts
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin-cloudflare";

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

Plugin Configuration

cloudflare(config?)

Creates the Cloudflare Vite plugin.
config
PluginConfig
Plugin configuration options
plugins
Plugin[]
Array of Vite plugins (the plugin returns multiple internal plugins)

Worker Configuration

WorkerConfig

The Worker configuration object extends Wrangler’s configuration with Vite-specific options. See Configuration Schema for the complete reference.

Utilities

getLocalWorkerdCompatibilityDate()

Get the recommended compatibility date for the local workerd version.
import { getLocalWorkerdCompatibilityDate } from "@cloudflare/vite-plugin-cloudflare";

const { date } = getLocalWorkerdCompatibilityDate();
console.log(date); // "2024-01-01"
result
{ date: string }
Object containing the recommended compatibility date

Development Examples

Basic Worker

// vite.config.ts
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin-cloudflare";

export default defineConfig({
  plugins: [
    cloudflare({
      configPath: "./wrangler.toml",
    }),
  ],
});
// src/index.ts
export default {
  async fetch(request, env, ctx) {
    return new Response("Hello from Vite + Cloudflare!");
  },
};

With Environment Overrides

// vite.config.ts
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin-cloudflare";

export default defineConfig({
  plugins: [
    cloudflare({
      configPath: "./wrangler.toml",
      config(workerConfig) {
        // Add development-only bindings
        if (process.env.NODE_ENV === "development") {
          workerConfig.vars = {
            ...workerConfig.vars,
            DEBUG: "true",
          };
        }
      },
    }),
  ],
});

Multi-Worker Setup

// vite.config.ts
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin-cloudflare";

export default defineConfig({
  plugins: [
    cloudflare({
      // Main worker
      configPath: "./wrangler.toml",
      viteEnvironment: {
        name: "main",
      },
      
      // Auxiliary workers
      auxiliaryWorkers: [
        {
          configPath: "./workers/auth/wrangler.toml",
          viteEnvironment: { name: "auth" },
        },
        {
          configPath: "./workers/api/wrangler.toml",
          viteEnvironment: { name: "api" },
        },
      ],
    }),
  ],
});
// src/index.ts (main worker)
export default {
  async fetch(request, env, ctx) {
    // Call auxiliary worker via service binding
    const authResponse = await env.AUTH_SERVICE.fetch(request);
    
    if (!authResponse.ok) {
      return new Response("Unauthorized", { status: 401 });
    }
    
    return new Response("Authenticated!");
  },
};

With Custom Persistence

// vite.config.ts
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin-cloudflare";

export default defineConfig({
  plugins: [
    cloudflare({
      persistState: {
        path: "./.dev/state",
      },
    }),
  ],
});

Pages Project

// vite.config.ts
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin-cloudflare";

export default defineConfig({
  plugins: [
    cloudflare({
      config: {
        name: "my-pages-project",
        compatibility_date: "2024-01-01",
        assets: {
          directory: "./public",
        },
      },
    }),
  ],
});

With Inspector

// vite.config.ts
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin-cloudflare";

export default defineConfig({
  plugins: [
    cloudflare({
      inspectorPort: 9229,
    }),
  ],
});
Then connect Chrome DevTools to chrome://inspect.

Build Configuration

The plugin automatically configures Vite for Workers compatibility:
  • Sets ssr.target to "webworker"
  • Configures resolve conditions: ["workerd", "worker", "browser"]
  • Handles Workers-specific module resolution
  • Bundles the Worker for deployment

Custom Build Options

// vite.config.ts
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin-cloudflare";

export default defineConfig({
  plugins: [cloudflare()],
  
  build: {
    target: "esnext",
    minify: true,
    sourcemap: true,
  },
  
  resolve: {
    alias: {
      "@": "/src",
    },
  },
});

Environment Variables

The plugin loads environment variables from .env files with CLOUDFLARE_ prefix:
# .env
CLOUDFLARE_ENV=staging
CLOUDFLARE_API_KEY=secret
Access in config:
// vite.config.ts
import { defineConfig, loadEnv } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin-cloudflare";

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), "CLOUDFLARE_");
  
  return {
    plugins: [
      cloudflare({
        config: {
          vars: {
            API_KEY: env.CLOUDFLARE_API_KEY,
          },
        },
      }),
    ],
  };
});

TypeScript Support

The plugin provides full TypeScript support:
import type { PluginConfig, WorkerConfig } from "@cloudflare/vite-plugin-cloudflare";

const workerConfig: WorkerConfig = {
  name: "my-worker",
  main: "src/index.ts",
  compatibility_date: "2024-01-01",
};

const pluginConfig: PluginConfig = {
  config: workerConfig,
  persistState: true,
};

Advanced Usage

Dynamic Configuration

// vite.config.ts
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin-cloudflare";

export default defineConfig(({ command, mode }) => {
  const isDev = command === "serve";
  const isProd = mode === "production";
  
  return {
    plugins: [
      cloudflare({
        config(workerConfig) {
          if (isDev) {
            // Development overrides
            workerConfig.vars = {
              ...workerConfig.vars,
              LOG_LEVEL: "debug",
            };
          }
          
          if (isProd) {
            // Production optimizations
            return {
              minify: true,
            };
          }
        },
      }),
    ],
  };
});

Conditional Bindings

// vite.config.ts
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin-cloudflare";

export default defineConfig({
  plugins: [
    cloudflare({
      config(workerConfig) {
        // Add analytics only in production
        if (process.env.ENABLE_ANALYTICS === "true") {
          workerConfig.analytics_engine_datasets = [
            { binding: "ANALYTICS" },
          ];
        }
      },
    }),
  ],
});

Custom Worker Entry

// vite.config.ts
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin-cloudflare";

export default defineConfig({
  plugins: [
    cloudflare({
      config: {
        name: "custom-worker",
        main: "./src/worker/index.ts",
      },
    }),
  ],
  
  build: {
    rollupOptions: {
      input: "./src/worker/index.ts",
    },
  },
});

Build docs developers (and LLMs) love