Skip to main content
The @sveltejs/adapter-cloudflare adapter deploys your SvelteKit app to Cloudflare Workers with static assets or Cloudflare Pages.

Installation

npm install -D @sveltejs/adapter-cloudflare wrangler

Usage

Add the adapter to your svelte.config.js:
/// file: svelte.config.js
import adapter from '@sveltejs/adapter-cloudflare';

/** @type {import('@sveltejs/kit').Config} */
const config = {
  kit: {
    adapter: adapter({
      routes: {
        include: ['/*'],
        exclude: ['<all>']
      }
    })
  }
};

export default config;

Configuration options

From the adapter type definitions:
/// file: packages/adapter-cloudflare/index.d.ts
export interface AdapterOptions {
  config?: string;      // Path to wrangler config
  fallback?: 'plaintext' | 'spa';  // 404 handling
  routes?: {
    include?: string[];  // Routes handled by functions
    exclude?: string[];  // Routes served as static assets
  };
  platformProxy?: GetPlatformProxyOptions;
}

config

Path to your Wrangler configuration file.
adapter({
  config: 'wrangler.toml'
})

fallback

Controls how 404 errors are handled:
  • 'plaintext' (default): Returns a simple “Not Found” text response
  • 'spa': Generates a SPA fallback page for client-side routing
adapter({
  fallback: 'spa'  // Better for client-side navigation
})
From the implementation:
/// file: packages/adapter-cloudflare/index.js
if (options.fallback === 'spa') {
  await builder.generateFallback(fallback);
} else {
  writeFileSync(fallback, 'Not Found');
}

routes

Only for Cloudflare Pages. Customizes the automatically-generated _routes.json file that controls routing.
adapter({
  routes: {
    include: ['/*'],
    exclude: ['<all>']  // Excludes all static assets
  }
})
The placeholders <build>, <files>, <prerendered>, and <all> are automatically expanded by the adapter.

platformProxy

Configuration passed to Wrangler’s getPlatformProxy during development:
adapter({
  platformProxy: {
    persist: true  // Persist KV/D1/R2 data between dev sessions
  }
})

Wrangler configuration

Create a wrangler.toml file in your project root:
name = "my-sveltekit-app"
compatibility_date = "2024-01-01"

pages_build_output_dir = ".vercel/output/static"

[env.production]
routes = [
  { pattern = "example.com", zone_name = "example.com" }
]

Environment bindings

Access Cloudflare bindings via the platform.env object:
/// file: src/routes/api/data/+server.js
/** @type {import('./$types').RequestHandler} */
export async function GET({ platform }) {
  const value = await platform.env.MY_KV.get('key');
  return new Response(value);
}
Define bindings in wrangler.toml:
[[kv_namespaces]]
binding = "MY_KV"
id = "your-kv-namespace-id"

[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "your-database-id"

[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "my-bucket"

Platform object

The platform object provides access to Cloudflare-specific APIs:
interface Platform {
  env: {
    // Your KV namespaces, D1 databases, R2 buckets, etc.
    [key: string]: any;
  };
  context: {
    waitUntil(promise: Promise<any>): void;
    passThroughOnException(): void;
  };
  caches: CacheStorage;
  cf: IncomingRequestCfProperties;
}
Example usage:
/// file: src/hooks.server.js
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
  // Access request metadata
  const country = event.platform.cf.country;
  
  // Use waitUntil for background tasks
  event.platform.context.waitUntil(
    logAnalytics(event.request)
  );
  
  const response = await resolve(event);
  response.headers.set('X-Country', country);
  
  return response;
}

Generated files

The adapter generates several Cloudflare-specific files:
.cloudflare/
├── _worker.js        # Worker entry point
├── _headers          # Custom headers
├── _redirects        # Redirect rules
└── _routes.json      # Routing configuration (Pages only)
Headers are automatically generated for immutable assets:
/// file: packages/adapter-cloudflare/index.js
function generate_headers(app_dir) {
  return `
# === START AUTOGENERATED SVELTE IMMUTABLE HEADERS ===
/${app_dir}/*
  X-Robots-Tag: noindex
  Cache-Control: no-cache
/${app_dir}/immutable/*
  ! Cache-Control
  Cache-Control: public, immutable, max-age=31536000
# === END AUTOGENERATED SVELTE IMMUTABLE HEADERS ===
`.trimEnd();
}

Deployment

1

Build your app

npm run build
2

Deploy to Cloudflare

wrangler pages deploy
For Cloudflare Pages, you can also connect your GitHub repository for automatic deployments.

Limitations

Cloudflare Workers have runtime limitations:
  • Maximum script size: 1 MB (after compression)
  • CPU time limit: 10-50ms per request (depends on plan)
  • No access to Node.js APIs