How to use adapter-cloudflare to deploy SvelteKit on Cloudflare


title: "How to use adapter-cloudflare to deploy SvelteKit on Cloudflare"
description: "An official-documentation-based guide to the Workers and Pages deployment paths, bindings, platform APIs, local verification, and common SvelteKit deployment mistakes."
slug: "sveltekit-cloudflare-adapter-2025"
tags: "SvelteKit, Cloudflare, Cloudflare Workers, Cloudflare Pages, adapter-cloudflare, Wrangler, serverless, web development"

When a SvelteKit project is deployed to Cloudflare, @sveltejs/adapter-cloudflare is more than a hosting switch. It turns the SvelteKit build into an output Cloudflare can run, and it connects server routes and static assets to Cloudflare’s delivery model. The current SvelteKit documentation says that this adapter supports all SvelteKit features and builds for both Cloudflare Workers Static Assets and Cloudflare Pages. Its older sibling, adapter-cloudflare-workers, targeted Workers Sites and is deprecated; it should not be the starting point for a new project.

Start with the meaningful distinction: Workers versus Pages

The adapter works with both products, but they do not consume the build in exactly the same way. With Cloudflare Workers, the Wrangler configuration in the project root is central. SvelteKit’s basic example points main at .svelte-kit/cloudflare/_worker.js and assets.directory at .svelte-kit/cloudflare. In other words, Wrangler deploys a Worker entry point for dynamic requests together with the static asset directory produced by the build.

With Cloudflare Pages, the Pages build configuration is the deployment contract. For Git integration, SvelteKit documents the SvelteKit framework preset, npm run build or vite build as the build command, and .svelte-kit/cloudflare as the build output directory. The same adapter output is used, but the adapter also generates _routes.json for Pages. Its routes.include and routes.exclude options are Pages-only controls. Excluded static paths do not invoke a Function, which can be faster and less expensive. The combined total of include and exclude rules is limited to 100, so a project with many prerendered URLs should consider sensible path patterns rather than enumerating every URL.

Cloudflare’s current Pages documentation recommends Workers as the primary platform for new applications because Workers covers most Pages use cases and has a broader feature set. That is not an instruction to migrate every healthy Pages application. A team that relies on the Pages Git-based preview workflow may reasonably keep it. The important point is to decide whether the service is governed by a Pages build configuration or by a Worker and Wrangler configuration, then validate the matching path rather than treating the two as interchangeable.

What the adapter does, and the smallest reliable setup

Install @sveltejs/adapter-cloudflare as a development dependency and register it in kit.adapter in svelte.config.js. The default adapter setup can be enough. Its config option is for locating a Wrangler configuration that uses a nonstandard filename, while platformProxy changes preferences for the emulated platform.env bindings used in development. Neither option replaces the need to define the real binding names and targets consistently in the Cloudflare/Wrangler configuration.

For an existing project with no Wrangler configuration file, modern Wrangler can detect SvelteKit and offer to generate the needed setup. According to Cloudflare, this can install the required adapter, create wrangler.jsonc, add useful package scripts, and update .gitignore. It is convenience, not a substitute for reviewing the deployment contract. wrangler setup --dry-run shows proposed changes without modifying files. Automatic configuration does not run when a Wrangler configuration already exists, and its dependency detection can be limited in monorepos because it analyzes the directory in which it runs rather than workspace-root dependencies.

Bindings and platform: keep runtime resources distinct from environment variables

Cloudflare’s env object holds project bindings such as KV namespaces and Durable Objects. The SvelteKit adapter passes that through the platform property to hooks and server endpoints, alongside ctx, caches, and cf. Server-side code can therefore reach Cloudflare-specific resources through platform?.env. In a TypeScript project, declaring the actual bindings in App.Platform within src/app.d.ts gives the codebase a useful check against drift between the code and the deployment configuration.

That does not mean every configuration value belongs under platform.env. SvelteKit explicitly recommends its built-in $env modules for environment variables. This separation is practical: a Cloudflare runtime binding is a connection to a platform resource, whereas SvelteKit’s environment-variable modules have their own semantics. Keeping them separate makes local behavior, type declarations, and future maintenance clearer.

Verify the built runtime, not only the development screen

Running npm run dev is a useful first check, but it is not the same as executing the adapter’s Cloudflare output. When the adapter is used directly, Cloudflare-specific values in platform are emulated in dev and preview modes; local bindings derived from the Wrangler configuration populate platform.env. SvelteKit recommends Wrangler 4 for build testing. After building, use wrangler dev .svelte-kit/cloudflare/_worker.js for a Workers build, or wrangler pages dev .svelte-kit/cloudflare for a Pages build.

By default, local development connects bindings to locally simulated resources. Cloudflare also supports remote connections on a binding-by-binding basis in wrangler dev and the Cloudflare Vite plugin. That provides a middle ground when one route must be exercised against a real remote resource. In contrast, wrangler dev --remote uploads and runs all Worker code on Cloudflare infrastructure and uses remote bindings. Cloudflare recommends local development with remote binding connections instead when faster iteration and debugging are the goals. Record which mode a test used: a test that silently touches a remote resource is materially different from one that uses a local simulation.

Deployment misconceptions worth removing early

One common mistake is assuming a root-level /functions directory will be combined with a SvelteKit Pages deployment. SvelteKit says that Functions in that directory are not included; server behavior should be implemented as SvelteKit server endpoints, which compile into a single _worker.js file.

Another is expecting _headers and _redirects at the project root to affect every response. They can be used for static asset responses, including images, but do not apply to SvelteKit responses rendered dynamically. Dynamic headers and redirects belong in a server endpoint or the handle hook.

Do not assume a Node server’s filesystem behavior carries over either. Cloudflare Workers cannot use fs. SvelteKit offers $app/server’s read function, which fetches from deployed public assets, or prerendering the relevant routes as alternatives. The SvelteKit server is bundled into a single file, and Wrangler can reject deployment if its minified size exceeds Worker limits; unnecessarily importing large server dependencies is a practical risk.

Finally, a 404 is not always just a client-router concern. In Workers, the behavior for an unmatched asset request depends on the default behavior and the assets.not_found_handling configuration. In Pages, the result is also affected by routes.exclude. The adapter’s fallback controls a plaintext 404 page versus a rendered SPA fallback, but a Workers assets.not_found_handling value of single-page-application causes the adapter to render the SPA index.html regardless of that fallback option. Before release, request a missing asset URL, a server route URL, and a prerendered URL separately and check both their status codes and bodies.

The adapter’s job is to produce a Cloudflare-compatible build. Reliable deployment depends on the decisions around it: which platform owns the deployment, whether bindings are local or remote during testing, and where dynamic-response behavior is implemented. Making those boundaries explicit prevents a configuration file from becoming a collection of guesses.

Primary source

https://svelte.dev/docs/kit/adapter-cloudflare
https://developers.cloudflare.com/workers/framework-guides/web-apps/sveltekit/

koen