diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/.eslintrc.cjs b/dev-packages/e2e-tests/test-applications/cloudflare-remix/.eslintrc.cjs
new file mode 100644
index 000000000000..4f6f59eee1e8
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/.eslintrc.cjs
@@ -0,0 +1,84 @@
+/**
+ * This is intended to be a basic starting point for linting in your app.
+ * It relies on recommended configs out of the box for simplicity, but you can
+ * and should modify this configuration to best suit your team's needs.
+ */
+
+/** @type {import('eslint').Linter.Config} */
+module.exports = {
+ root: true,
+ parserOptions: {
+ ecmaVersion: "latest",
+ sourceType: "module",
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
+ env: {
+ browser: true,
+ commonjs: true,
+ es6: true,
+ },
+ ignorePatterns: ["!**/.server", "!**/.client"],
+
+ // Base config
+ extends: ["eslint:recommended"],
+
+ overrides: [
+ // React
+ {
+ files: ["**/*.{js,jsx,ts,tsx}"],
+ plugins: ["react", "jsx-a11y"],
+ extends: [
+ "plugin:react/recommended",
+ "plugin:react/jsx-runtime",
+ "plugin:react-hooks/recommended",
+ "plugin:jsx-a11y/recommended",
+ ],
+ settings: {
+ react: {
+ version: "detect",
+ },
+ formComponents: ["Form"],
+ linkComponents: [
+ { name: "Link", linkAttribute: "to" },
+ { name: "NavLink", linkAttribute: "to" },
+ ],
+ "import/resolver": {
+ typescript: {},
+ },
+ },
+ },
+
+ // Typescript
+ {
+ files: ["**/*.{ts,tsx}"],
+ plugins: ["@typescript-eslint", "import"],
+ parser: "@typescript-eslint/parser",
+ settings: {
+ "import/internal-regex": "^~/",
+ "import/resolver": {
+ node: {
+ extensions: [".ts", ".tsx"],
+ },
+ typescript: {
+ alwaysTryTypes: true,
+ },
+ },
+ },
+ extends: [
+ "plugin:@typescript-eslint/recommended",
+ "plugin:import/recommended",
+ "plugin:import/typescript",
+ ],
+ },
+
+ // Node
+ {
+ files: [".eslintrc.cjs"],
+ env: {
+ node: true,
+ },
+ },
+ ],
+};
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/.gitignore b/dev-packages/e2e-tests/test-applications/cloudflare-remix/.gitignore
new file mode 100644
index 000000000000..464354906a64
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/.gitignore
@@ -0,0 +1,8 @@
+node_modules
+
+/.cache
+/build
+.env
+.dev.vars
+
+.wrangler
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/.npmrc b/dev-packages/e2e-tests/test-applications/cloudflare-remix/.npmrc
new file mode 100644
index 000000000000..070f80f05092
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/.npmrc
@@ -0,0 +1,2 @@
+@sentry:registry=http://127.0.0.1:4873
+@sentry-internal:registry=http://127.0.0.1:4873
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/README.md b/dev-packages/e2e-tests/test-applications/cloudflare-remix/README.md
new file mode 100644
index 000000000000..dec7f30b37ac
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/README.md
@@ -0,0 +1,47 @@
+# Welcome to Remix + Cloudflare!
+
+- 📖 [Remix docs](https://remix.run/docs)
+- 📖 [Remix Cloudflare docs](https://remix.run/guides/vite#cloudflare)
+
+## Development
+
+Run the dev server:
+
+```sh
+npm run dev
+```
+
+To run Wrangler:
+
+```sh
+npm run build
+npm run start
+```
+
+## Typegen
+
+Generate types for your Cloudflare bindings in `wrangler.toml`:
+
+```sh
+npm run typegen
+```
+
+You will need to rerun typegen whenever you make changes to `wrangler.toml`.
+
+## Deployment
+
+First, build your app for production:
+
+```sh
+npm run build
+```
+
+Then, deploy your app to Cloudflare Pages:
+
+```sh
+npm run deploy
+```
+
+## Styling
+
+This template comes with [Tailwind CSS](https://tailwindcss.com/) already configured for a simple default starting experience. You can use whatever css framework you prefer. See the [Vite docs on css](https://vitejs.dev/guide/features.html#css) for more information.
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/app/entry.client.tsx b/dev-packages/e2e-tests/test-applications/cloudflare-remix/app/entry.client.tsx
new file mode 100644
index 000000000000..94d5dc0de0fa
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/app/entry.client.tsx
@@ -0,0 +1,18 @@
+/**
+ * By default, Remix will handle hydrating your app on the client for you.
+ * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
+ * For more information, see https://remix.run/file-conventions/entry.client
+ */
+
+import { RemixBrowser } from "@remix-run/react";
+import { startTransition, StrictMode } from "react";
+import { hydrateRoot } from "react-dom/client";
+
+startTransition(() => {
+ hydrateRoot(
+ document,
+
+
+
+ );
+});
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/app/entry.server.tsx b/dev-packages/e2e-tests/test-applications/cloudflare-remix/app/entry.server.tsx
new file mode 100644
index 000000000000..0d5c40a755e6
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/app/entry.server.tsx
@@ -0,0 +1,43 @@
+/**
+ * By default, Remix will handle generating the HTTP Response for you.
+ * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
+ * For more information, see https://remix.run/file-conventions/entry.server
+ */
+
+import type { AppLoadContext, EntryContext } from "@remix-run/cloudflare";
+import { RemixServer } from "@remix-run/react";
+import { isbot } from "isbot";
+import { renderToReadableStream } from "react-dom/server";
+
+export default async function handleRequest(
+ request: Request,
+ responseStatusCode: number,
+ responseHeaders: Headers,
+ remixContext: EntryContext,
+ // This is ignored so we can keep it in the template for visibility. Feel
+ // free to delete this parameter in your app if you're not using it!
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ loadContext: AppLoadContext
+) {
+ const body = await renderToReadableStream(
+ ,
+ {
+ signal: request.signal,
+ onError(error: unknown) {
+ // Log streaming rendering errors from inside the shell
+ console.error(error);
+ responseStatusCode = 500;
+ },
+ }
+ );
+
+ if (isbot(request.headers.get("user-agent") || "")) {
+ await body.allReady;
+ }
+
+ responseHeaders.set("Content-Type", "text/html");
+ return new Response(body, {
+ headers: responseHeaders,
+ status: responseStatusCode,
+ });
+}
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/app/root.tsx b/dev-packages/e2e-tests/test-applications/cloudflare-remix/app/root.tsx
new file mode 100644
index 000000000000..3d3d73320719
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/app/root.tsx
@@ -0,0 +1,30 @@
+import {
+ Links,
+ Meta,
+ Outlet,
+ Scripts,
+ ScrollRestoration,
+} from "@remix-run/react";
+import "./tailwind.css";
+
+export function Layout({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
+
+
+
+
+
+ {children}
+
+
+
+
+ );
+}
+
+export default function App() {
+ return ;
+}
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/app/routes/_index.tsx b/dev-packages/e2e-tests/test-applications/cloudflare-remix/app/routes/_index.tsx
new file mode 100644
index 000000000000..5c68e88b6e2f
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/app/routes/_index.tsx
@@ -0,0 +1,41 @@
+import type { MetaFunction } from "@remix-run/cloudflare";
+
+export const meta: MetaFunction = () => {
+ return [
+ { title: "New Remix App" },
+ {
+ name: "description",
+ content: "Welcome to Remix on Cloudflare!",
+ },
+ ];
+};
+
+export default function Index() {
+ return (
+
+
Welcome to Remix on Cloudflare
+
+
+ );
+}
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/app/tailwind.css b/dev-packages/e2e-tests/test-applications/cloudflare-remix/app/tailwind.css
new file mode 100644
index 000000000000..b5c61c956711
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/app/tailwind.css
@@ -0,0 +1,3 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/functions/[[path]].ts b/dev-packages/e2e-tests/test-applications/cloudflare-remix/functions/[[path]].ts
new file mode 100644
index 000000000000..08576b33f177
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/functions/[[path]].ts
@@ -0,0 +1,13 @@
+import { createPagesFunctionHandler } from '@remix-run/cloudflare-pages';
+import { sentryPagesPlugin } from '@sentry/cloudflare';
+
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore - the server build file is generated by `remix vite:build`
+// eslint-disable-next-line import/no-unresolved
+import * as build from '../build/server';
+
+export const onRequest = [
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (context: any) => sentryPagesPlugin({ dsn: context.env.E2E_TEST_DSN })(context),
+ createPagesFunctionHandler({ build }),
+];
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/load-context.ts b/dev-packages/e2e-tests/test-applications/cloudflare-remix/load-context.ts
new file mode 100644
index 000000000000..2777ca18c051
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/load-context.ts
@@ -0,0 +1,17 @@
+import { type PlatformProxy } from "wrangler";
+
+// When using `wrangler.toml` to configure bindings,
+// `wrangler types` will generate types for those bindings
+// into the global `Env` interface.
+// Need this empty interface so that typechecking passes
+// even if no `wrangler.toml` exists.
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+interface Env {}
+
+type Cloudflare = Omit, "dispose">;
+
+declare module "@remix-run/cloudflare" {
+ interface AppLoadContext {
+ cloudflare: Cloudflare;
+ }
+}
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/package.json b/dev-packages/e2e-tests/test-applications/cloudflare-remix/package.json
new file mode 100644
index 000000000000..cefbf34c9f98
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/package.json
@@ -0,0 +1,52 @@
+{
+ "name": "cloudflare-remix",
+ "private": true,
+ "sideEffects": false,
+ "type": "module",
+ "scripts": {
+ "build": "remix vite:build",
+ "deploy": "wrangler pages deploy ./build/client",
+ "dev": "remix vite:dev",
+ "lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .",
+ "start": "wrangler pages dev ./build/client --binding=E2E_TEST_DSN=$E2E_TEST_DSN --port=$PORT",
+ "typecheck": "tsc",
+ "typegen": "wrangler types",
+ "test:build": "pnpm install && npx playwright install && pnpm build",
+ "test:assert": "pnpm playwright test"
+ },
+ "dependencies": {
+ "@sentry/cloudflare": "latest || *",
+ "@remix-run/cloudflare": "^2.10.3",
+ "@remix-run/cloudflare-pages": "^2.10.3",
+ "@remix-run/react": "^2.10.3",
+ "isbot": "^4.1.0",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "devDependencies": {
+ "@cloudflare/workers-types": "^4.20240512.0",
+ "@sentry-internal/test-utils": "link:../../../test-utils",
+ "@playwright/test": "^1.44.1",
+ "@remix-run/dev": "^2.10.3",
+ "@types/react": "^18.2.20",
+ "@types/react-dom": "^18.2.7",
+ "@typescript-eslint/eslint-plugin": "^6.7.4",
+ "@typescript-eslint/parser": "^6.7.4",
+ "autoprefixer": "^10.4.19",
+ "eslint": "^8.38.0",
+ "eslint-import-resolver-typescript": "^3.6.1",
+ "eslint-plugin-import": "^2.28.1",
+ "eslint-plugin-jsx-a11y": "^6.7.1",
+ "eslint-plugin-react": "^7.33.2",
+ "eslint-plugin-react-hooks": "^4.6.0",
+ "postcss": "^8.4.38",
+ "tailwindcss": "^3.4.4",
+ "typescript": "^5.1.6",
+ "vite": "^5.1.0",
+ "vite-tsconfig-paths": "^4.2.1",
+ "wrangler": "3.57.1"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+}
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/playwright.config.mjs b/dev-packages/e2e-tests/test-applications/cloudflare-remix/playwright.config.mjs
new file mode 100644
index 000000000000..fc1939297a31
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/playwright.config.mjs
@@ -0,0 +1,7 @@
+import { getPlaywrightConfig } from '@sentry-internal/test-utils';
+
+const config = getPlaywrightConfig({
+ // startCommand: 'pnpm start',
+});
+
+export default config;
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/postcss.config.js b/dev-packages/e2e-tests/test-applications/cloudflare-remix/postcss.config.js
new file mode 100644
index 000000000000..2aa7205d4b40
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/postcss.config.js
@@ -0,0 +1,6 @@
+export default {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+};
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/public/_headers b/dev-packages/e2e-tests/test-applications/cloudflare-remix/public/_headers
new file mode 100644
index 000000000000..f9e277752020
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/public/_headers
@@ -0,0 +1,4 @@
+/favicon.ico
+ Cache-Control: public, max-age=3600, s-maxage=3600
+/assets/*
+ Cache-Control: public, max-age=31536000, immutable
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/public/_routes.json b/dev-packages/e2e-tests/test-applications/cloudflare-remix/public/_routes.json
new file mode 100644
index 000000000000..b042b3ec08ab
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/public/_routes.json
@@ -0,0 +1,5 @@
+{
+ "version": 1,
+ "include": ["/*"],
+ "exclude": ["/favicon.ico", "/assets/*"]
+}
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/public/favicon.ico b/dev-packages/e2e-tests/test-applications/cloudflare-remix/public/favicon.ico
new file mode 100644
index 000000000000..8830cf6821b3
Binary files /dev/null and b/dev-packages/e2e-tests/test-applications/cloudflare-remix/public/favicon.ico differ
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/start-event-proxy.mjs b/dev-packages/e2e-tests/test-applications/cloudflare-remix/start-event-proxy.mjs
new file mode 100644
index 000000000000..05c02137ae73
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/start-event-proxy.mjs
@@ -0,0 +1,6 @@
+import { startEventProxyServer } from '@sentry-internal/test-utils';
+
+startEventProxyServer({
+ port: 3031,
+ proxyServerName: 'cloudflare-remix',
+});
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/tailwind.config.ts b/dev-packages/e2e-tests/test-applications/cloudflare-remix/tailwind.config.ts
new file mode 100644
index 000000000000..34d03da55f6e
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/tailwind.config.ts
@@ -0,0 +1,9 @@
+import type { Config } from "tailwindcss";
+
+export default {
+ content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+} satisfies Config;
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/tests/transaction.test.ts b/dev-packages/e2e-tests/test-applications/cloudflare-remix/tests/transaction.test.ts
new file mode 100644
index 000000000000..1c30b2a23927
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/tests/transaction.test.ts
@@ -0,0 +1,37 @@
+import { expect, test } from '@playwright/test';
+
+import { waitForTransaction } from '@sentry-internal/test-utils';
+
+test('Should send a transaction', async ({ page }) => {
+ const transactionPromise = waitForTransaction('cloudflare-remix', async transactionEvent => {
+ return transactionEvent?.transaction === 'GET /';
+ });
+
+ await page.goto(`/`);
+
+ await expect(transactionPromise).resolves.toBeDefined();
+
+ const transactionEvent = await transactionPromise;
+
+ expect(transactionEvent.spans).toContainEqual(
+ expect.objectContaining({
+ data: expect.objectContaining({
+ 'http.method': 'GET',
+ 'sentry.op': 'http.client',
+ 'sentry.origin': 'auto.http.otel.node_fetch',
+ }),
+ description: 'GET http://example.com/',
+ }),
+ );
+
+ expect(transactionEvent.spans).toContainEqual(
+ expect.objectContaining({
+ data: expect.objectContaining({
+ 'http.method': 'GET',
+ 'sentry.op': 'http.client',
+ 'sentry.origin': 'auto.http.otel.http',
+ }),
+ description: 'GET http://example.com/',
+ }),
+ );
+});
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/tsconfig.json b/dev-packages/e2e-tests/test-applications/cloudflare-remix/tsconfig.json
new file mode 100644
index 000000000000..a61e663a7651
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/tsconfig.json
@@ -0,0 +1,32 @@
+{
+ "include": [
+ "**/*.ts",
+ "**/*.tsx",
+ "**/.server/**/*.ts",
+ "**/.server/**/*.tsx",
+ "**/.client/**/*.ts",
+ "**/.client/**/*.tsx"
+ ],
+ "compilerOptions": {
+ "lib": ["DOM", "DOM.Iterable", "ES2022"],
+ "types": ["@remix-run/cloudflare", "vite/client"],
+ "isolatedModules": true,
+ "esModuleInterop": true,
+ "jsx": "react-jsx",
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "resolveJsonModule": true,
+ "target": "ES2022",
+ "strict": true,
+ "allowJs": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "baseUrl": ".",
+ "paths": {
+ "~/*": ["./app/*"]
+ },
+
+ // Vite takes care of building everything, not tsc.
+ "noEmit": true
+ }
+}
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/vite.config.ts b/dev-packages/e2e-tests/test-applications/cloudflare-remix/vite.config.ts
new file mode 100644
index 000000000000..8c8a052d9af3
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/vite.config.ts
@@ -0,0 +1,20 @@
+import {
+ vitePlugin as remix,
+ cloudflareDevProxyVitePlugin as remixCloudflareDevProxy,
+} from "@remix-run/dev";
+import { defineConfig } from "vite";
+import tsconfigPaths from "vite-tsconfig-paths";
+
+export default defineConfig({
+ plugins: [
+ remixCloudflareDevProxy(),
+ remix({
+ future: {
+ v3_fetcherPersist: true,
+ v3_relativeSplatPath: true,
+ v3_throwAbortReason: true,
+ },
+ }),
+ tsconfigPaths(),
+ ],
+});
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/worker-configuration.d.ts b/dev-packages/e2e-tests/test-applications/cloudflare-remix/worker-configuration.d.ts
new file mode 100644
index 000000000000..5b2319b3f29f
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/worker-configuration.d.ts
@@ -0,0 +1,4 @@
+// Generated by Wrangler
+// After adding bindings to `wrangler.toml`, regenerate this interface via `npm run cf-typegen`
+interface Env {
+}
diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-remix/wrangler.toml b/dev-packages/e2e-tests/test-applications/cloudflare-remix/wrangler.toml
new file mode 100644
index 000000000000..396cc92a62da
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/cloudflare-remix/wrangler.toml
@@ -0,0 +1,87 @@
+#:schema node_modules/wrangler/config-schema.json
+name = "cloudflare-remix"
+compatibility_date = "2024-07-25"
+pages_build_output_dir = "./build/client"
+
+compatibility_flags = ["nodejs_als"]
+
+# Automatically place your workloads in an optimal location to minimize latency.
+# If you are running back-end logic in a Pages Function, running it closer to your back-end infrastructure
+# rather than the end user may result in better performance.
+# Docs: https://developers.cloudflare.com/pages/functions/smart-placement/#smart-placement
+# [placement]
+# mode = "smart"
+
+# Variable bindings. These are arbitrary, plaintext strings (similar to environment variables)
+# Docs:
+# - https://developers.cloudflare.com/pages/functions/bindings/#environment-variables
+# Note: Use secrets to store sensitive data.
+# - https://developers.cloudflare.com/pages/functions/bindings/#secrets
+# [vars]
+# MY_VARIABLE = "production_value"
+
+# Bind the Workers AI model catalog. Run machine learning models, powered by serverless GPUs, on Cloudflare’s global network
+# Docs: https://developers.cloudflare.com/pages/functions/bindings/#workers-ai
+# [ai]
+# binding = "AI"
+
+# Bind a D1 database. D1 is Cloudflare’s native serverless SQL database.
+# Docs: https://developers.cloudflare.com/pages/functions/bindings/#d1-databases
+# [[d1_databases]]
+# binding = "MY_DB"
+# database_name = "my-database"
+# database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
+
+# Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model.
+# Durable Objects can live for as long as needed. Use these when you need a long-running "server", such as in realtime apps.
+# Docs: https://developers.cloudflare.com/workers/runtime-apis/durable-objects
+# [[durable_objects.bindings]]
+# name = "MY_DURABLE_OBJECT"
+# class_name = "MyDurableObject"
+# script_name = 'my-durable-object'
+
+# Bind a KV Namespace. Use KV as persistent storage for small key-value pairs.
+# Docs: https://developers.cloudflare.com/pages/functions/bindings/#kv-namespaces
+# [[kv_namespaces]]
+# binding = "MY_KV_NAMESPACE"
+# id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+
+# Bind a Queue producer. Use this binding to schedule an arbitrary task that may be processed later by a Queue consumer.
+# Docs: https://developers.cloudflare.com/pages/functions/bindings/#queue-producers
+# [[queues.producers]]
+# binding = "MY_QUEUE"
+# queue = "my-queue"
+
+# Bind an R2 Bucket. Use R2 to store arbitrarily large blobs of data, such as files.
+# Docs: https://developers.cloudflare.com/pages/functions/bindings/#r2-buckets
+# [[r2_buckets]]
+# binding = "MY_BUCKET"
+# bucket_name = "my-bucket"
+
+# Bind another Worker service. Use this binding to call another Worker without network overhead.
+# Docs: https://developers.cloudflare.com/pages/functions/bindings/#service-bindings
+# [[services]]
+# binding = "MY_SERVICE"
+# service = "my-service"
+
+# To use different bindings for preview and production environments, follow the examples below.
+# When using environment-specific overrides for bindings, ALL bindings must be specified on a per-environment basis.
+# Docs: https://developers.cloudflare.com/pages/functions/wrangler-configuration#environment-specific-overrides
+
+######## PREVIEW environment config ########
+
+# [env.preview.vars]
+# API_KEY = "xyz789"
+
+# [[env.preview.kv_namespaces]]
+# binding = "MY_KV_NAMESPACE"
+# id = ""
+
+######## PRODUCTION environment config ########
+
+# [env.production.vars]
+# API_KEY = "abc123"
+
+# [[env.production.kv_namespaces]]
+# binding = "MY_KV_NAMESPACE"
+# id = ""