feat: cloudflare workers adapter (#8214)

This commit is contained in:
Kermout Ayoub
2026-01-02 13:39:31 +01:00
committed by GitHub
parent 505e454fee
commit a748c30057
15 changed files with 625 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
---
'create-qwik': patch
---
feat: cloudflare workers deployment adapter

View File

@@ -32,6 +32,13 @@ test('Deployments Cloudflare Pages Adapter page loads', async ({ page }) => {
);
});
test('Deployments Cloudflare Workers Adapter page loads', async ({ page }) => {
await page.goto('/docs/deployments/cloudflare-workers/');
await expect(page).toHaveTitle(
'Cloudflare Workers Adapter and Middleware | Deployments 📚 Qwik Documentation'
);
});
test('Deployments Deno Middleware page loads', async ({ page }) => {
await page.goto('/docs/deployments/deno/');
await expect(page).toHaveTitle('Deno Middleware | Deployments 📚 Qwik Documentation');

View File

@@ -139,6 +139,7 @@ test('docs page loads', async ({ page }) => {
'Firebase',
'Google Cloud Run',
'Cloudflare Pages',
'Cloudflare Workers',
'Deno',
'Bun',
'Netlify Edge',

View File

@@ -0,0 +1,425 @@
---
title: Cloudflare Workers Adapter and Middleware | Deployments
---
import PackageManagerTabs from '~/components/package-manager-tabs/index.tsx';
# Cloudflare Workers Adapter
Qwik City Cloudflare Workers adapter allows you to connect Qwik City to [Cloudflare Workers](https://workers.cloudflare.com/).
## Installation
To integrate the `cloudflare-workers` adapter, use the `add` command:
<PackageManagerTabs>
<span q:slot="pnpm">
```shell
pnpm run qwik add cloudflare-workers
```
</span>
<span q:slot="npm">
```shell
npm run qwik add cloudflare-workers
```
</span>
<span q:slot="yarn">
```shell
yarn run qwik add cloudflare-workers
```
</span>
<span q:slot="bun">
```shell
bun run qwik add cloudflare-workers
```
</span>
</PackageManagerTabs>
The adapter will add a new `vite.config.ts` within the `adapters/` directory, a new entry file, and a `wrangler.jsonc` configuration file:
```shell
└── adapters/
└── cloudflare-workers/
└── vite.config.ts
└── src/
└── entry.cloudflare-pages.tsx
└── wrangler.jsonc
└── worker-configuration.d.ts
```
Additionally, within the `package.json`, the following scripts will be added:
- `"cf-typegen": "wrangler types"` - Generate TypeScript types for your Worker bindings
- `"serve": "wrangler dev"` - Start a local development server
- `"deploy": "wrangler deploy"` - Deploy your Worker to Cloudflare
## Configuration
### TypeScript Configuration
Add the Cloudflare Workers types to your `tsconfig.json`:
```json title="tsconfig.json"
{
"compilerOptions": {
"types": [
"@cloudflare/workers-types/2023-07-01",
"node"
]
}
}
```
This enables TypeScript autocompletion for Cloudflare Workers APIs and bindings.
### Vite Configuration
To enable local development with access to your Worker's bindings (KV, R2, D1, etc.), update your `vite.config.ts`:
```ts title="vite.config.ts"
import { defineConfig, type UserConfig } from "vite";
import { qwikVite } from "@builder.io/qwik/optimizer";
import { qwikCity } from "@builder.io/qwik-city/vite";
import tsconfigPaths from "vite-tsconfig-paths";
let platform = {};
if (process.env.NODE_ENV === 'development') {
const { getPlatformProxy } = await import('wrangler');
platform = await getPlatformProxy();
}
export default defineConfig(({ command, mode }): UserConfig => {
return {
plugins: [
qwikCity({
platform
}),
// the rest of your code
```
The `getPlatformProxy` function provides access to your Worker's bindings during local development, allowing you to test KV, R2, D1, and other Cloudflare resources locally.
### Wrangler Configuration
The `wrangler.jsonc` file contains your Worker's configuration. Make sure to update the `name` field to match your project:
```jsonc title="wrangler.jsonc"
{
"name": "my-qwik-app", // 👈 Change this to your Worker's name
"main": "./dist/_worker.js",
"compatibility_date": "2025-12-28",
// ... rest of configuration
}
```
After adding any bindings (KV, R2, D1, etc.) to `wrangler.jsonc`, regenerate the TypeScript types:
<PackageManagerTabs>
<span q:slot="pnpm">
```shell
pnpm run cf-typegen
```
</span>
<span q:slot="npm">
```shell
npm run cf-typegen
```
</span>
<span q:slot="yarn">
```shell
yarn run cf-typegen
```
</span>
<span q:slot="bun">
```shell
bun run cf-typegen
```
</span>
</PackageManagerTabs>
This will update the `worker-configuration.d.ts` file with proper types for your bindings.
## Local Development
To start a local development server with your Worker:
<PackageManagerTabs>
<span q:slot="pnpm">
```shell
pnpm run serve
```
</span>
<span q:slot="npm">
```shell
npm run serve
```
</span>
<span q:slot="yarn">
```shell
yarn run serve
```
</span>
<span q:slot="bun">
```shell
bun run serve
```
</span>
</PackageManagerTabs>
This will start Wrangler's development server, typically at `http://localhost:8787/`.
## Production Build
To build the application for production, use the `build` command, this command will automatically run `build.server` and `build.client`:
<PackageManagerTabs>
<span q:slot="pnpm">
```shell
pnpm run build
```
</span>
<span q:slot="npm">
```shell
npm run build
```
</span>
<span q:slot="yarn">
```shell
yarn run build
```
</span>
<span q:slot="bun">
```shell
bun run build
```
</span>
</PackageManagerTabs>
[Read the full guide here](https://github.com/QwikDev/qwik/tree/main/starters/adapters/cloudflare-workers/README.md)
## Deploy to Cloudflare Workers
After installing the integration the project is ready to be deployed to Cloudflare Workers.
If the nodejs version is different in your environment than Cloudflare Workers (v16.20.2) you'll need to add a `NODE_VERSION` environment variable and set the value to the version that you got from running the `node -v` command in your environment:
Then deploy your Worker:
<PackageManagerTabs>
<span q:slot="pnpm">
```shell
pnpm run deploy
```
</span>
<span q:slot="npm">
```shell
npm run deploy
```
</span>
<span q:slot="yarn">
```shell
yarn run deploy
```
</span>
<span q:slot="bun">
```shell
bun run deploy
```
</span>
</PackageManagerTabs>
Your Worker will be deployed to `https://your-worker-name.your-subdomain.workers.dev`.
Note that you will need a [Cloudflare account](https://dash.cloudflare.com/sign-up) in order to complete this step.
## Environment Variables
Cloudflare Workers support two types of environment variables:
### Build-Time Variables
Build-time variables are set in the Cloudflare Dashboard and are available during the build process. These are useful for configuration that doesn't change between deployments.
To set build-time variables:
1. Go to **Workers & Pages** in your Cloudflare Dashboard
2. Select your Worker
3. Go to **Settings > Build**
4. Add your variables under **Variables and secrets** (not to be confused by Variables and secrets thats right under domains section)
### Runtime Variables
Runtime variables are defined in your `wrangler.jsonc` file using the `vars` property:
```jsonc title="wrangler.jsonc"
{
"name": "my-qwik-app",
"vars": {
"MY_VARIABLE": "production_value",
"API_URL": "https://api.example.com"
}
}
```
## Custom Domains
You can attach custom domains to your Worker for production use:
1. Go to **Workers & Pages** in your Cloudflare Dashboard
2. Select your Worker
3. Go to **Settings > Triggers > Custom Domains**
4. Click **Add Custom Domain**
5. Enter your domain name (e.g., `app.example.com`)
6. Follow the instructions to update your DNS settings
For more details, see the [Cloudflare Custom Domains documentation](https://developers.cloudflare.com/workers/configuration/routing/custom-domains/).
## Advanced
### Cloudflare Workers Entry Middleware
When the `cloudflare-workers` adapter is added, a new entry file will be created at `src/entry.cloudflare-pages.tsx`. Below is an example of using the built-in middleware within the entry file.
```tsx title="src/entry.cloudflare-pages.tsx"
import {
createQwikCity,
type PlatformCloudflarePages as PlatformCloudflareWorkers,
} from '@builder.io/qwik-city/middleware/cloudflare-pages';
import qwikCityPlan from '@qwik-city-plan';
import render from './entry.ssr';
const fetch = createQwikCity({ render, qwikCityPlan });
export { fetch };
```
The compiled middleware will be built in the `server/` directory. The build process also creates a `_worker.js` file in the `dist/` directory, which is the entry point for your Cloudflare Worker.
```tsx title="/dist/_worker.js"
import { fetch } from "../server/entry.cloudflare-pages";
export default { fetch };
```
This file exports the `fetch` handler that Cloudflare Workers uses to handle incoming requests.
### Bindings
Cloudflare Workers can access various Cloudflare resources through bindings. These are configured in your `wrangler.jsonc` file:
#### KV Namespace
```jsonc title="wrangler.jsonc"
{
"kv_namespaces": [
{
"binding": "MY_KV",
"id": "your-kv-namespace-id"
}
]
}
```
Access in your code:
```ts
export const onGet = async ({ platform }) => {
const value = await platform.env.MY_KV.get('key');
};
```
#### R2 Bucket
```jsonc title="wrangler.jsonc"
{
"r2_buckets": [
{
"binding": "MY_BUCKET",
"bucket_name": "my-bucket"
}
]
}
```
#### D1 Database
```jsonc title="wrangler.jsonc"
{
"d1_databases": [
{
"binding": "DB",
"database_name": "my-database",
"database_id": "your-database-id"
}
]
}
```
After adding any bindings, remember to regenerate types:
<PackageManagerTabs>
<span q:slot="pnpm">
```shell
pnpm run cf-typegen
```
</span>
<span q:slot="npm">
```shell
npm run cf-typegen
```
</span>
<span q:slot="yarn">
```shell
yarn run cf-typegen
```
</span>
<span q:slot="bun">
```shell
bun run cf-typegen
```
</span>
</PackageManagerTabs>
For more information on bindings, see the [Cloudflare Workers Bindings documentation](https://developers.cloudflare.com/workers/runtime-apis/bindings/).
### Context and Platform Access
You can access Cloudflare Worker's environment variables, bindings, and context in your endpoint methods through the `platform` parameter:
```ts
export const onRequest = async ({ platform }) => {
// Access environment variables
const secret = platform.env['SUPER_SECRET_TOKEN'];
// Access KV namespace
const value = await platform.env.MY_KV.get('key');
// Access D1 databases
const result = await platform.env.DB.prepare('SELECT * FROM users').all();
};
```
For better type safety, import the `RequestHandler` and `PlatformCloudflareWorkers` types:
```tsx
import { type RequestHandler } from '@builder.io/qwik-city';
import { type PlatformCloudflarePages as PlatformCloudflareWorkers } from '@builder.io/qwik-city/middleware/cloudflare-pages';
export const onGet: RequestHandler<PlatformCloudflareWorkers> = async ({ platform }) => {
// TypeScript will provide autocompletion for platform.env
//...
};
```
The `platform` object provides access to:
- `platform.env` - Environment variables, secrets, and bindings (KV, R2, D1, etc.)
- Request context and metadata
For more information, see the [Cloudflare Workers Runtime APIs documentation](https://developers.cloudflare.com/workers/runtime-apis/).

View File

@@ -95,6 +95,7 @@
- [Firebase](deployments/firebase/index.mdx)
- [Google Cloud Run](deployments/gcp-cloud-run/index.mdx)
- [Cloudflare Pages](deployments/cloudflare-pages/index.mdx)
- [Cloudflare Workers](deployments/cloudflare-workers/index.mdx)
- [Deno](deployments/deno/index.mdx)
- [Bun](deployments/bun/index.mdx)
- [Netlify Edge](deployments/netlify-edge/index.mdx)

View File

@@ -0,0 +1,52 @@
## Cloudflare Workers
Cloudflare's [wrangler](https://github.com/cloudflare/wrangler) CLI can be used to preview a production build locally. To start a local server, run:
```
npm run serve
```
Then visit [http://localhost:8787/](http://localhost:8787/)
### Deployments
[Cloudflare Workers](https://workers.cloudflare.com/) can be deployed using the [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/).
If you don't already have an account, then [create a Cloudflare account here](https://dash.cloudflare.com/sign-up/workers-and-pages).
Once authenticated, you can deploy your Worker:
```
npm run deploy
```
### Configuration
The `wrangler.jsonc` file contains your Worker configuration. Key settings include:
- **name**: Your Worker's name
- **main**: Path to your Worker script (default: `./dist/_worker.js`)
- **compatibility_date**: The date used for compatibility with the Workers runtime
- **assets**: Configuration for serving static assets
- **bindings**: Resources your Worker can interact with (KV, R2, D1, etc.)
After adding any binding, use this command to regenerate the worker-configuration.d.ts file
```
npm run cf-typegen
```
For more details, see the [Wrangler configuration documentation](https://developers.cloudflare.com/workers/wrangler/configuration/).
### Bindings
Cloudflare Workers can interact with various Cloudflare resources through bindings:
- **KV**: Key-value storage
- **R2**: Object storage
- **D1**: SQL database
- **Durable Objects**: Strongly consistent storage
- **Queues**: Message queues
- **AI**: AI inference
Configure bindings in your `wrangler.jsonc` file. See the [bindings documentation](https://developers.cloudflare.com/workers/runtime-apis/bindings/) for more information.

View File

@@ -0,0 +1,15 @@
import { cloudflarePagesAdapter as cloudflareWorkersAdapter } from "@builder.io/qwik-city/adapters/cloudflare-pages/vite";
import { extendConfig } from "@builder.io/qwik-city/vite";
import baseConfig from "../../vite.config";
export default extendConfig(baseConfig, () => {
return {
build: {
ssr: true,
rollupOptions: {
input: ["src/entry.cloudflare-pages.tsx", "@qwik-city-plan"],
},
},
plugins: [cloudflareWorkersAdapter()],
};
});

View File

@@ -0,0 +1,3 @@
# Cloudflare
functions/**/*.js
.wrangler/

View File

@@ -0,0 +1,31 @@
{
"description": "Cloudflare Workers",
"scripts": {
"build.server": "qwik check-client src dist && vite build -c adapters/cloudflare-workers/vite.config.ts",
"deploy": "wrangler deploy",
"serve": "wrangler dev",
"cf-typegen": "wrangler types"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20251228.0",
"wrangler": "^3.0.0"
},
"__qwik__": {
"priority": 40,
"displayName": "Adapter: Cloudflare Workers",
"docs": [
"https://qwik.dev/deployments/cloudflare-workers/",
"https://developers.cloudflare.com/workers"
],
"nextSteps": {
"title": "Next Steps",
"lines": [
"Make sure to follow the instructions in the [Cloudflare Workers documentation](https://qwik.dev/deployments/cloudflare-workers/) to setup your Qwik app.",
"Now you can build and deploy to Cloudflare Workers with:",
"",
"- pnpm run build: production build for Cloudflare",
"- pnpm run deploy: it will use the Cloudflare CLI to deploy your site"
]
}
}
}

View File

@@ -0,0 +1,4 @@
_worker.js
_routes.json
_headers
_redirects

View File

@@ -0,0 +1,11 @@
# https://developers.cloudflare.com/pages/platform/headers/
/*service-worker.js
Cache-Control: no-store
Content-Type: application/javascript
X-Content-Type-Options: nosniff
/build/*
Cache-Control: public, max-age=31536000, s-maxage=31536000, immutable
/assets/*
Cache-Control: public, max-age=31536000, s-maxage=31536000, immutable

View File

@@ -0,0 +1 @@
# https://developers.cloudflare.com/pages/platform/redirects/

View File

@@ -0,0 +1,23 @@
/*
* WHAT IS THIS FILE?
*
* It's the entry point for Cloudflare Workers when building for production.
*
* Learn more about the Cloudflare Workers integration here:
* - https://qwik.dev/docs/deployments/cloudflare-workers/
*
*/
import {
createQwikCity,
type PlatformCloudflarePages as PlatformCloudflareWorkers,
} from "@builder.io/qwik-city/middleware/cloudflare-pages";
import qwikCityPlan from "@qwik-city-plan";
import render from "./entry.ssr";
declare global {
type QwikCityPlatform = PlatformCloudflareWorkers;
}
const fetch = createQwikCity({ render, qwikCityPlan });
export { fetch };

View File

@@ -0,0 +1,5 @@
// Generated by Wrangler
// After adding bindings to `wrangler.jsonc`, regenerate this interface via `npm run cf-typegen`
interface Env {
ASSET: Fetcher;
}

View File

@@ -0,0 +1,41 @@
/**
* For more details on how to configure Wrangler, refer to:
* https://developers.cloudflare.com/workers/wrangler/configuration/
*/
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-qwik-app",
"main": "./dist/_worker.js",
"compatibility_date": "2025-12-28",
"compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"],
"assets": {
"binding": "ASSET",
"directory": "./dist",
},
"observability": {
"enabled": true,
},
/**
* Smart Placement
* https://developers.cloudflare.com/workers/configuration/smart-placement/#smart-placement
*/
// "placement": { "mode": "smart" }
/**
* Bindings
* Bindings allow your Worker to interact with resources on the Cloudflare Developer Platform, including
* databases, object storage, AI inference, real-time communication and more.
* https://developers.cloudflare.com/workers/runtime-apis/bindings/
*/
/**
* Environment Variables
* https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables
* Note: Use secrets to store sensitive data.
* https://developers.cloudflare.com/workers/configuration/secrets/
*/
// "vars": { "MY_VARIABLE": "production_value" }
/**
* Service Bindings (communicate between multiple Workers)
* https://developers.cloudflare.com/workers/wrangler/configuration/#service-bindings
*/
// "services": [ { "binding": "MY_SERVICE", "service": "my-service" } ]
}