Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
2f12c15
cloudflare
ottomated Aug 20, 2026
0756638
netlify
ottomated Aug 20, 2026
3711f70
node
ottomated Aug 20, 2026
7a60529
vercel
ottomated Aug 20, 2026
f7f8f63
breaking: replace the `generateManifest` adapter api with `writeServe…
ottomated Aug 20, 2026
47a0434
fix cloudflare
ottomated Aug 20, 2026
b1e7adb
unused
ottomated Aug 20, 2026
afcd825
address most of suggestions
ottomated Aug 21, 2026
cb57f4a
bun :(
ottomated Aug 22, 2026
ac11ed1
fix bun tests
ottomated Aug 24, 2026
f48dc2d
fix bun again
ottomated Aug 24, 2026
687f11e
add service worker to manifest
ottomated Aug 24, 2026
4b231f3
fix broken tests
ottomated Aug 24, 2026
c9fb18d
breaking: remove `SSRManifest` from public types
ottomated Aug 20, 2026
6eeee75
chore: flatten SSRManifest
ottomated Aug 20, 2026
b3bbb20
feat: move `basePath` and `prerenderedRoutes` to the public SSRManife…
ottomated Aug 17, 2026
424211d
feat: allow adapters to override getRequest and setResponse
ottomated Aug 12, 2026
c25786c
changeset
ottomated Aug 12, 2026
7bbec86
generate types
ottomated Aug 12, 2026
7786c6c
optional chaining
ottomated Aug 12, 2026
e344900
docs
ottomated Aug 12, 2026
f00e723
regen types
ottomated Aug 13, 2026
afe953c
remove cloudflare `platform`, emulate the `cloudflare:workers` module…
ottomated Aug 12, 2026
fa7d5cb
support Request.cf
ottomated Aug 12, 2026
e75e460
fix ai stuff
ottomated Aug 12, 2026
4d6ed3e
don't run proxy during build
ottomated Aug 12, 2026
c92a75f
remove platform from built worker
ottomated Aug 12, 2026
db3ef5e
update docs
ottomated Aug 12, 2026
1729142
typo in docs
ottomated Aug 13, 2026
e118590
add dev/preview comment
ottomated Aug 14, 2026
31a1e0e
types
ottomated Aug 14, 2026
339220a
apply comments
ottomated Aug 14, 2026
922ee66
mock tracing
ottomated Aug 14, 2026
1036de3
type safety for virtual module
ottomated Aug 15, 2026
a9f47fa
use global proxy's existance as prerendering signal
ottomated Aug 15, 2026
cecdc77
types!!
ottomated Aug 15, 2026
b73ee39
fix types
ottomated Aug 15, 2026
6704303
remove prepare script
ottomated Aug 15, 2026
e930979
doc types
ottomated Aug 15, 2026
db9e1f3
doc types 2
ottomated Aug 15, 2026
a7516ea
build cloudflare environment
ottomated Aug 14, 2026
80de570
fix lockfile
ottomated Aug 15, 2026
a59357c
wip
ottomated Aug 16, 2026
7bdb76c
wip
teemingc Aug 16, 2026
02757f8
empty
teemingc Aug 16, 2026
5f3181c
empty
teemingc Aug 16, 2026
85430f7
Update env-vars.js
teemingc Aug 16, 2026
674784c
Update packages/kit/src/core/postbuild/analyse.js
teemingc Aug 16, 2026
184e9f9
fix merge changes
teemingc Aug 16, 2026
30b7403
fixes
teemingc Aug 16, 2026
dd7e917
fix check
teemingc Aug 16, 2026
fa20259
fix
teemingc Aug 16, 2026
9f8956e
fix
teemingc Aug 16, 2026
014d72c
fix preview always expecting ssr output
teemingc Aug 17, 2026
e180adc
comment
teemingc Aug 17, 2026
c06e199
skip ssr if output is completely prerendered
teemingc Aug 17, 2026
70a2164
changeset
teemingc Aug 17, 2026
03f7782
fix hash router trying to load client code on server during dev
teemingc Aug 17, 2026
1d9c263
remove internal references from wrangler config
ottomated Aug 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/early-eggs-crash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@sveltejs/kit": minor
"@sveltejs/adapter-vercel": minor
"@sveltejs/adapter-node": minor
"@sveltejs/adapter-cloudflare": minor
---

feat: move `basePath` and `prerenderedRoutes` to the public SSRManifest api

6 changes: 6 additions & 0 deletions .changeset/flat-cases-see.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@sveltejs/kit": major
---

breaking: remove `SSRManifest` from public types

6 changes: 6 additions & 0 deletions .changeset/fuzzy-kings-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@sveltejs/adapter-cloudflare": major
---

breaking: remove cloudflare `platform`, emulate the `cloudflare:workers` module instead

6 changes: 6 additions & 0 deletions .changeset/rare-schools-itch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@sveltejs/kit": minor
---

feat: allow adapters to override getRequest and setResponse

6 changes: 6 additions & 0 deletions .changeset/shy-apes-prove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@sveltejs/kit": minor
---

feat: skip SSR build if a server is not required

10 changes: 10 additions & 0 deletions .changeset/smooth-flies-begin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@sveltejs/adapter-cloudflare": major
"@sveltejs/adapter-netlify": major
"@sveltejs/adapter-node": major
"@sveltejs/adapter-vercel": major
"@sveltejs/kit": major
---

breaking: replace the `generateManifest` adapter api with `writeServerEntrypoint` and `builder.manifest`

56 changes: 14 additions & 42 deletions documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: Cloudflare

To deploy to [Cloudflare Workers](https://workers.cloudflare.com/) or [Cloudflare Pages](https://pages.cloudflare.com/), use [`adapter-cloudflare`](https://github.com/sveltejs/kit/tree/main/packages/adapter-cloudflare).

This adapter will be installed by default when you use [`adapter-auto`](adapter-auto). If you plan on staying with Cloudflare, you can switch from [`adapter-auto`](adapter-auto) to using this adapter directly so that `event.platform` is emulated during local development, type declarations are automatically applied, and the ability to set Cloudflare-specific options is provided.
This adapter will be installed by default when you use [`adapter-auto`](adapter-auto). If you plan on staying with Cloudflare, you can switch from [`adapter-auto`](adapter-auto) to using this adapter directly so that `cloudflare:workers` is emulated during local development, type declarations are automatically applied, and the ability to set Cloudflare-specific options is provided.

## Comparisons

Expand Down Expand Up @@ -53,7 +53,7 @@ Path to your [Wrangler configuration file](https://developers.cloudflare.com/wor

### platformProxy

Preferences for the emulated `platform.env` local bindings. See the [getPlatformProxy](https://developers.cloudflare.com/workers/wrangler/api/#parameters-1) Wrangler API documentation for a full list of options.
Preferences for the emulated `env` local bindings. See the [getPlatformProxy](https://developers.cloudflare.com/workers/wrangler/api/#parameters-1) Wrangler API documentation for a full list of options.

### fallback

Expand Down Expand Up @@ -130,62 +130,34 @@ Functions contained in the [`/functions` directory](https://developers.cloudflar

## Runtime APIs

The [`env`](https://developers.cloudflare.com/workers/runtime-apis/fetch-event#parameters) object contains your project's [bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/), which consist of KV/DO namespaces, etc. It is passed to SvelteKit via the `platform` property, along with [`ctx`](https://developers.cloudflare.com/workers/runtime-apis/context/), [`caches`](https://developers.cloudflare.com/workers/runtime-apis/cache/), and [`cf`](https://developers.cloudflare.com/workers/runtime-apis/request/#incomingrequestcfproperties), meaning that you can access it in hooks and endpoints:
The [`env`](https://developers.cloudflare.com/workers/runtime-apis/fetch-event#parameters) object contains your project's [bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/), which consist of KV/DO namespaces, etc. It is available on the [`cloudflare:workers`](https://developers.cloudflare.com/workers/runtime-apis/bindings/#importing-env-as-a-global) module.

```js
/// file: +server.js
// @filename: ambient.d.ts
import { DurableObjectNamespace } from '@cloudflare/workers-types';

declare global {
namespace App {
interface Platform {
env: {
YOUR_DURABLE_OBJECT_NAMESPACE: DurableObjectNamespace;
};
}
}
declare module 'cloudflare:workers' {
export const env: {
YOUR_DURABLE_OBJECT_NAMESPACE: import('@cloudflare/workers-types').DurableObjectNamespace;
};
}
// @filename: +server.js
// ---cut---
// @errors: 2355 2322
/// file: +server.js
import { env } from 'cloudflare:workers';

/** @type {import('./$types').RequestHandler} */
export async function POST({ request, platform }) {
const x = platform?.env.YOUR_DURABLE_OBJECT_NAMESPACE.idFromName('x');
export async function POST() {
const x = env.YOUR_DURABLE_OBJECT_NAMESPACE.idFromName('x');
}
```

> [!NOTE] SvelteKit's built-in [`$app/env/*` modules](environment-variables) should be preferred for environment variables.

To make these types available to your app, install [`wrangler`](https://www.npmjs.com/package/wrangler), run [`wrangler types`](https://developers.cloudflare.com/workers/languages/typescript/), and reference them in your `src/app.d.ts`:

```ts
// @filename: ambient.d.ts
import { KVNamespace, DurableObjectNamespace } from '@cloudflare/workers-types';

namespace Cloudflare {
export interface Env {
YOUR_KV_NAMESPACE: KVNamespace;
YOUR_DURABLE_OBJECT_NAMESPACE: DurableObjectNamespace;
}
}
/// file: src/app.d.ts
// ---cut---

declare global {
namespace App {
interface Platform {
+++ env: Cloudflare.Env;+++
}
}
}

export {};
```
To make these types available to your app, install [`wrangler`](https://www.npmjs.com/package/wrangler) and run [`wrangler types`](https://developers.cloudflare.com/workers/languages/typescript/).

### Testing locally

Cloudflare specific values in the `platform` property are emulated during dev and preview modes. Local [bindings](https://developers.cloudflare.com/workers/wrangler/configuration/#bindings) are created based on your [Wrangler configuration file](https://developers.cloudflare.com/workers/wrangler/) and are used to populate `platform.env` during development and preview. Use the adapter config [`platformProxy` option](#Options-platformProxy) to change your preferences for the bindings.
Cloudflare specific values are emulated during dev and preview modes. Local [bindings](https://developers.cloudflare.com/workers/wrangler/configuration/#bindings) are created based on your [Wrangler configuration file](https://developers.cloudflare.com/workers/wrangler/) and are used to populate `env` during development and preview. Use the adapter config [`platformProxy` option](#Options-platformProxy) to change your preferences for the bindings.

> [!NOTE] [Durable Objects](https://developers.cloudflare.com/durable-objects/) and [Workflows](https://developers.cloudflare.com/workflows/), which require custom classes to be exported from your worker, are not currently supported.

Expand Down
17 changes: 14 additions & 3 deletions documentation/docs/25-build-and-deploy/99-writing-adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ type AdapterSpecificOptions = any;

// @filename: index.js
// ---cut---
import { getRequest, setResponse } from '@sveltejs/kit/node';

/** @param {AdapterSpecificOptions} options */
export default function (options) {
/** @type {import('@sveltejs/kit').Adapter} */
Expand Down Expand Up @@ -40,6 +42,15 @@ export default function (options) {
// Return `false if it can't, or throw a descriptive error.
}
},
getRequest(options) {
const request = getRequest(options);
// modify the Request object here if needed
return request;
},
setResponse(res, response) {
// handle WebSockets here, for example
setResponse(res, response);
},
vite: {
plugins: {
// add plugins here to integrate with Vite
Expand All @@ -53,15 +64,15 @@ export default function (options) {
}
```

Of these, `name` and `adapt` are required. `emulate`, `vite`, and `supports` are optional.
Of these, `name` and `adapt` are required. `emulate`, `vite`, `getRequest`, `setResponse`, and `supports` are optional.

Within the `adapt` method, there are a number of things that an adapter should do:

- Clear out the build directory
- Write SvelteKit output with `builder.writeClient`, `builder.writeServer`, and `builder.writePrerendered`
- Output code that:
- Imports `Server` from `${builder.getServerDirectory()}/index.js`
- Instantiates the app with a manifest generated with `builder.generateManifest({ relativePath })`
- Imports a `server` instance generated by `${builder.writeServerEntrypoint()}`
- Runs `await server.init({ env, read })`
- Listens for requests from the platform, converts them to a standard [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) if necessary, calls the `server.respond(request, { getClientAddress })` function to generate a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) and responds with it
- expose any platform-specific information to SvelteKit via the `platform` option passed to `server.respond`
- Bundle the output to avoid needing to install dependencies on the target platform, if necessary
Expand Down
38 changes: 37 additions & 1 deletion documentation/docs/60-appendix/35-migrating-to-sveltekit-3.md
Original file line number Diff line number Diff line change
Expand Up @@ -453,9 +453,45 @@ All first-party adapters now require SvelteKit 3, alongside these adapter-specif

### `adapter-cloudflare`

Cloudflare-specific APIs are no longer available on `platform`. Instead, find them where you would expect on a Cloudflare worker:

- `env`, `ctx.waitUntil`, and other `ctx` properties should be imported from `cloudflare:workers`:
```js
// @filename: ambient.d.ts
declare module 'cloudflare:workers' {
export const env: { KV: { get(): Promise<unknown> } };
export function waitUntil(promise: Promise<any>): void;
}
// ---cut---
import { env, waitUntil } from 'cloudflare:workers';

const value = await env.KV.get('key');
```
- `cf` is now a property of the `Request` object:
```js
/// file: src/routes/cf/+server.js
// @filename: ambient.d.ts
interface Request {
cf: import('@cloudflare/workers-types').IncomingRequestCfProperties;
}
// @filename: index.js
// @errors: 7031
// ---cut---
export async function GET({ request }) {
const { country } = request.cf;
}
```
- `caches` is now a global variable:
```js
/// file: src/routes/cache/+server.js
let request = new Request('');
// ---cut---
const myCache = await caches.open('foo');
await myCache.match(request);
```

- minimum `wrangler` is now `^4.67.0`
- `@cloudflare/workers-types` upgraded
- `platform.context` removed in favour of `platform.ctx`

### `adapter-node`

Expand Down
8 changes: 6 additions & 2 deletions packages/adapter-bun/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,13 @@ export default function (opts = {}) {
const manifest_file = path.resolve(server, 'manifest.js');
const server_options_file = path.resolve(src_dir, 'options.js');

const tmp = builder.getBuildDirectory('bun-tmp');
fs.mkdirSync(tmp, { recursive: true });
builder.writeServerEntrypoint(`${tmp}/server.js`);

const virtual_files = {
[manifest_file]:
`export const manifest = ${builder.generateManifest({ relativePath: './' })};\n` +
`export const app_dir = ${JSON.stringify(builder.config.appDir)};\n` +
`export const base = ${JSON.stringify(builder.config.paths.base || '/')};\n` +
`export const embed = ${JSON.stringify(!!buildOptions.compile)};\n` +
`export const env_prefix = ${JSON.stringify(envPrefix)};\n` +
Expand Down Expand Up @@ -198,7 +202,7 @@ export default function (opts = {}) {
name: 'adapter-bun',
setup(build) {
build.onResolve({ filter: /^(SERVER|MANIFEST|ROUTES|SERVER_OPTIONS)$/ }, ({ path }) => {
if (path === 'SERVER') return { path: `${server}/index.js` };
if (path === 'SERVER') return { path: `${tmp}/server.js` };
if (path === 'MANIFEST') return { path: manifest_file };
if (path === 'ROUTES') return { path: routes_file };
if (path === 'SERVER_OPTIONS') return { path: server_options_file };
Expand Down
4 changes: 2 additions & 2 deletions packages/adapter-bun/internal.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
declare module 'MANIFEST' {
export const manifest: import('@sveltejs/kit').SSRManifest;
export const app_dir: string;
export const base: string;
export const embed: boolean;
export const env_prefix: string;
Expand All @@ -12,7 +12,7 @@ declare module 'ROUTES' {
}

declare module 'SERVER' {
export { Server } from '@sveltejs/kit';
export const server: import('@sveltejs/kit').Server;
}

declare module 'SERVER_OPTIONS' {
Expand Down
6 changes: 2 additions & 4 deletions packages/adapter-bun/src/handler.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
/** @import { Server as BunServer } from 'bun' */
import { Server } from 'SERVER';
import { manifest, origin, env_prefix } from 'MANIFEST';
import { server } from 'SERVER';
import { origin, env_prefix } from 'MANIFEST';
import { server_assets } from 'ROUTES';
import { env, number_env } from './env.js';

const server = new Server(manifest);

const address_header = env('ADDRESS_HEADER', '').toLowerCase();
const protocol_header = env('PROTOCOL_HEADER', '').toLowerCase();
const host_header = env('HOST_HEADER', '').toLowerCase();
Expand Down
4 changes: 2 additions & 2 deletions packages/adapter-bun/src/routes-util.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** @import { BunFile, BunRequest, Serve } from 'bun' */
import { manifest, base, embed } from 'MANIFEST';
import { app_dir, base, embed } from 'MANIFEST';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

Expand Down Expand Up @@ -174,7 +174,7 @@ function file_route(file, meta, extra_headers = {}) {
* @returns {Array<[string, RouteHandler]>}
*/
export function client_asset(url, filename = url, meta) {
const immutable = url.startsWith(`${manifest.appDir}/immutable/`);
const immutable = url.startsWith(`${app_dir}/immutable/`);
const route = file_route(
resolve_file('client', filename),
meta,
Expand Down
13 changes: 9 additions & 4 deletions packages/adapter-bun/test/adapter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ describe('Bun build configuration', () => {

const files = bun_build.mock.calls[0][0].files;
expect(files[manifest_file]).toBe(
'export const manifest = {"appDir":"_app"};\n' +
'export const app_dir = "_app";\n' +
'export const base = "/docs";\n' +
'export const embed = false;\n' +
'export const env_prefix = "APP_";\n' +
Expand All @@ -130,7 +130,9 @@ describe('Bun build configuration', () => {
expect(files[options_file]).toBe(
'export default {"hostname":"127.0.0.1","port":4000,"development":true};'
);
expect(builder.generateManifest).toHaveBeenCalledWith({ relativePath: './' });
expect(builder.writeServerEntrypoint).toHaveBeenCalledWith(
'.svelte-kit/output/bun-tmp/server.js'
);
});

test('resolves generated runtime modules through the Bun plugin', async () => {
Expand All @@ -144,7 +146,7 @@ describe('Bun build configuration', () => {
);
const resolve_module = on_resolve.mock.calls[0][1];
expect(resolve_module({ path: 'SERVER' })).toEqual({
path: '.svelte-kit/output/server/index.js'
path: '.svelte-kit/output/bun-tmp/server.js'
});
expect(resolve_module({ path: 'MANIFEST' })).toEqual({ path: manifest_file });
expect(resolve_module({ path: 'ROUTES' })).toEqual({ path: routes_file });
Expand Down Expand Up @@ -576,7 +578,7 @@ function create_builder({
instrumentation?: boolean;
} = {}) {
return {
config: { outDir: '.svelte-kit', paths: { base, origin } },
config: { outDir: '.svelte-kit', paths: { base, origin }, appDir: '_app' },
routes,
prerendered: {
pages: new Map(prerendered_pages),
Expand All @@ -588,6 +590,9 @@ function create_builder({
warn: mock((_message: string) => {}),
info: mock((_message: string) => {})
},
getAppPath: () => `${base}/_app`,
writeServerEntrypoint: mock(() => {}),
getBuildDirectory: (dir: string) => `.svelte-kit/output/${dir}`,
getServerDirectory: () => '.svelte-kit/output/server',
writeClient: mock(() => client_files),
writePrerendered: mock(() => prerendered_files),
Expand Down
Loading
Loading