Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
ffdecc3
Add SvelteKit resource and cloudflare-sveltekit example with KV/R2 bi…
acoyfellow Jun 3, 2025
1bbc076
feat(examples): add cloudflare-sveltekit example
acoyfellow Jun 3, 2025
72312e1
Merge branch 'sam-goodwin:main' into cloudflare-sveltekit-example
acoyfellow Jun 3, 2025
fed0678
docs: update README with additional Cloudflare examples
acoyfellow Jun 3, 2025
fec79c0
Merge branch 'sam-goodwin:main' into cloudflare-sveltekit-example
acoyfellow Jun 4, 2025
a40bebb
fix(cloudflare): update SvelteKit entry point and asset paths
acoyfellow Jun 4, 2025
2cbd291
fix(cloudflare): enhance SvelteKit configuration and compatibility ch…
acoyfellow Jun 4, 2025
280eb0f
refactor(cloudflare):
acoyfellow Jun 4, 2025
e431045
docs(cloudflare): enhance README about CF binding and types
acoyfellow Jun 4, 2025
7e81192
docs(cloudflare): add guide for deploying SvelteKit apps
acoyfellow Jun 4, 2025
be84faa
Merge branch 'sam-goodwin:main' into cloudflare-sveltekit-example
acoyfellow Jun 4, 2025
87c9f2f
Merge branch 'sam-goodwin:main' into cloudflare-sveltekit-example
acoyfellow Jun 5, 2025
1098e37
chore(cloudflare): update dependencies and enhance SvelteKit guide fo…
acoyfellow Jun 5, 2025
6a68fa3
fix: resolve biome formatting and linting violations
acoyfellow Jun 6, 2025
ad323cc
Merge branch 'sam-goodwin:main' into cloudflare-sveltekit-example
acoyfellow Jun 6, 2025
823cb91
Merge branch 'main' into cloudflare-sveltekit-example
sam-goodwin Jun 9, 2025
1c7ef1a
fix r2 adoption
sam-goodwin Jun 9, 2025
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
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,14 @@ await app.finalize();

# Examples

- CloudFlare Worker with Queue, R2 Bucket, Durable Objects, Workflows and RPC: [examples/cloudflare-worker/](./examples/cloudflare-worker/alchemy.run.ts)
- CloudFlare Worker Bootstrap with Queue and R2 End-to-End Testing: [examples/cloudflare-worker-bootstrap/](./examples/cloudflare-worker-bootstrap/index.ts)
- CloudFlare ViteJS Website + API Backend with Durable Objects: [examples/cloudflare-vite/](./examples/cloudflare-vite/alchemy.run.ts)
- CloudFlare TanStack Start Application Deployment: [examples/cloudflare-tanstack-start/](./examples/cloudflare-tanstack-start/alchemy.run.ts)
- CloudFlare RedwoodJS Application with D1 Database: [examples/cloudflare-redwood/](./examples/cloudflare-redwood/alchemy.run.ts)
- CloudFlare React Router Application Deployment: [examples/cloudflare-react-router/](./examples/cloudflare-react-router/alchemy.run.ts)
- CloudFlare Nuxt 3 Application with Pipeline and R2 Bucket: [examples/cloudflare-nuxt-pipeline/](./examples/cloudflare-nuxt-pipeline/alchemy.run.ts)
- CloudFlare SvelteKit Application with KV and R2 Storage: [examples/cloudflare-sveltekit/](./examples/cloudflare-sveltekit/alchemy.run.ts)
- Deploy an AWS Lambda Function with a DynamoDB Table and IAM Role: [examples/aws-app/](./examples/aws-app/alchemy.run.ts)

# Getting Started
Expand Down
156 changes: 156 additions & 0 deletions alchemy-web/docs/guides/cloudflare-sveltekit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
---
order: 3
title: SvelteKit
description: Step-by-step guide to deploying a SvelteKit application to Cloudflare Workers using Alchemy with KV storage and R2 buckets.
---

# SvelteKit

This guide walks through how to deploy a SvelteKit application to Cloudflare Workers with Alchemy.

## Create a new SvelteKit Project

Start by creating a new SvelteKit project:

```sh
bun create svelte@latest my-sveltekit-app
cd my-sveltekit-app
bun install
```

> [!NOTE]
> See Svelte's [Introduction](https://svelte.dev/docs/kit/introduction) guide for more details on SvelteKit applications.
## Install Cloudflare Adapter and Dependencies

Install the required dependencies:

```sh
bun add @sveltejs/adapter-cloudflare alchemy cloudflare
bun add -D @cloudflare/workers-types
```

## Configure SvelteKit for Cloudflare

Update your `svelte.config.js` to use the Cloudflare adapter:

```js
import adapter from '@sveltejs/adapter-cloudflare';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';

/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: vitePreprocess(),
kit: {
adapter: adapter()
}
};

export default config;
```

## Create `alchemy.run.ts`

Create an `alchemy.run.ts` file in the root of your project:

```ts
import alchemy from "alchemy";
import { KVNamespace, R2Bucket, SvelteKit } from "alchemy/cloudflare";

const app = await alchemy("my-sveltekit-app", {
stage: process.env.USER ?? "dev",
phase: process.argv.includes("--destroy") ? "destroy" : "up",
});

const website = await SvelteKit("sveltekit-website", {
bindings: {
AUTH_STORE: await KVNamespace("auth-store", {
title: "my-sveltekit-auth-store",
}),
STORAGE: await R2Bucket("storage", {
allowPublicAccess: false,
}),
},
url: true,
});

console.log({
url: website.url,
});

await app.finalize();
```

## Configure SvelteKit Types

Update `src/app.d.ts` for Cloudflare bindings:

```ts
declare global {
namespace App {
interface Platform {
env: {
STORAGE: R2Bucket;
AUTH_STORE: KVNamespace;
};
context: ExecutionContext;
caches: CacheStorage & { default: Cache };
}
}
}

export {};
```

## Using Cloudflare Bindings

In your SvelteKit routes, access Cloudflare resources via `platform.env`:

```ts
// +page.server.ts
export const load = async ({ platform }) => {
const kvData = await platform?.env?.AUTH_STORE?.get('some-key');
const r2Object = await platform?.env?.STORAGE?.get('some-file');
return { kvData };
};
```
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also:

import { env } from "cloudflare:workers"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

works fine at runtime, but SK's SSR build tries to import it in node which doesn't understand the cloudflare: protocol

I tried using Alchemy's cloudflareWorkersDevEnvironmentShim() plugin, but it only applies during dev (apply: "serve").

Any ideas for making the import work during build, or should we stick with platform.env for SSR routes?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh that's very interesting. Maybe cloudflare's template works around that? Otherwise I don't have a solution. It would need to run it in miniflare.


## Deploy Your Application

Login to Cloudflare:

```sh
wrangler login
```

Run your Alchemy script to deploy the application:

```sh
bun ./alchemy.run
```

It should output the URL of your deployed site:

```sh
{
url: "https://your-site.your-sub-domain.workers.dev",
}
```

## Local Development

To run your application locally:

```sh
bun run dev
```

## Tear Down

When you're finished experimenting, you can tear down the application:

```sh
bun ./alchemy.run --destroy
```

This will remove all Cloudflare resources created by this deployment.
2 changes: 2 additions & 0 deletions alchemy/src/cloudflare/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export * from "./r2-rest-state-store.ts";
export * from "./react-router.ts";
export * from "./redwood.ts";
export * from "./route.ts";
export * from "./sveltekit.ts";
export * from "./tanstack-start.ts";
export * from "./vectorize-index.ts";
export * from "./vectorize-metadata-index.ts";
Expand All @@ -41,3 +42,4 @@ export * from "./worker.ts";
export { Workflow } from "./workflow.ts";
export * from "./wrangler.json.ts";
export * from "./zone.ts";

73 changes: 73 additions & 0 deletions alchemy/src/cloudflare/sveltekit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { join } from "node:path";
import type { Assets } from "./assets.ts";
import type { Bindings } from "./bindings.ts";
import { Website, type WebsiteProps } from "./website.ts";
import type { Worker } from "./worker.ts";

export interface SvelteKitProps<B extends Bindings> extends WebsiteProps<B> {}

// don't allow the ASSETS to be overriden
export type SvelteKit<B extends Bindings> = B extends { ASSETS: any }
? never
: Worker<B & { ASSETS: Assets }>;

/**
* Deploy a SvelteKit application to Cloudflare Workers with automatically configured defaults.
*
* This resource handles the deployment of SvelteKit applications with optimized settings for
* Cloudflare Workers, including proper build commands and compatibility flags. It expects
* the SvelteKit app to be configured with the @sveltejs/adapter-cloudflare adapter.
*
* For local development, SvelteKit provides excellent built-in dev server support with
* emulated platform.env bindings for Cloudflare-specific APIs.
*
* @see https://svelte.dev/docs/kit/adapter-cloudflare - Official SvelteKit Cloudflare adapter docs
*
* @example
* // Deploy a basic SvelteKit application
* const svelteApp = await SvelteKit("my-svelte-app");
*
* @example
* // Deploy with Cloudflare bindings
* import { D1Database, KVNamespace, R2Bucket } from "alchemy/cloudflare";
*
* const database = await D1Database("svelte-db");
* const sessions = await KVNamespace("sessions");
* const storage = await R2Bucket("app-storage");
*
* const svelteApp = await SvelteKit("svelte-with-bindings", {
* bindings: {
* DB: database,
* AUTH_STORE: sessions,
* STORAGE: storage
* }
* });
*
* @param id - Unique identifier for the SvelteKit application
* @param props - Configuration properties for the SvelteKit deployment
* @returns A Cloudflare Worker resource representing the deployed SvelteKit application
*/
export async function SvelteKit<B extends Bindings>(
id: string,
props?: Partial<SvelteKitProps<B>>,
): Promise<SvelteKit<B>> {

if (props?.compatibilityDate) {
const providedDate = new Date(props.compatibilityDate);
const minDate = new Date("2024-09-23");
if (providedDate < minDate) {
throw new Error(
`SvelteKit compatibility date must be >= 2024-09-23 for nodejs_compat support, got ${props.compatibilityDate}`
);
}
}

return Website(id, {
...props,
command: props?.command ?? "bun run build",
main: props?.main ?? join(".svelte-kit", "cloudflare", "_worker.js"),
assets: props?.assets ?? join(".svelte-kit", "cloudflare"),
compatibilityFlags: ["nodejs_compat", ...(props?.compatibilityFlags ?? [])],
compatibilityDate: props?.compatibilityDate,
});
}
Loading