Configuration

cloudflare.config.ts: a practical guide

Define a Worker and its bindings with typed helpers. Start with the smallest configuration, then add only the resources your application uses.

Beta tooling changes quickly. Examples are checked against cf 1.0.0-beta.5 and @cloudflare/config 0.20.0. See the sources below.

Start with a Worker

cloudflare.config.ts
import { defineConfig } from "cf/config";

export default defineConfig({
  worker: {
    name: "notes-worker",
    compatibilityDate: "2026-09-29",
    entrypoint: "./src/index.ts",
  },
});

Put this file at your project root. This example describes a plain TypeScript Worker whose source is src/index.ts. It still needs a supported build integration; the config alone is not a build system.

Why TypeScript?

defineConfig gives your editor a typed shape for the configuration. Binding helpers expose supported options through autocomplete. The configuration can also be a function, which lets you compute mode-specific values explicitly.

The new shape uses camelCase fields such as compatibilityDate. Copying a Wrangler JSON object into this file without conversion leaves you with the wrong structure. Use cf migrate for an existing Wrangler project.

Add bindings under worker.env

cloudflare.config.ts
import { bindings, defineConfig } from "cf/config";

export default defineConfig({
  worker: {
    name: "notes-worker",
    compatibilityDate: "2026-09-29",
    entrypoint: "./src/index.ts",
    env: {
      DB: bindings.d1({ name: "notes-db" }),
      UPLOADS: bindings.r2({ name: "notes-uploads" }),
      API_TOKEN: bindings.secret(),
    },
  },
});

DB, UPLOADS and API_TOKEN are application-facing names. The database and bucket names inside the helpers refer to resources. A secret declaration is not a secret value: supply values through the documented deployment or secret-management workflow.

The focused examples cover D1, R2, KV and Durable Objects. Use the config builder to combine them into a starting point.

Select a mode explicitly

cloudflare.config.ts
import { bindings, defineConfig } from "cf/config";

export default defineConfig(({ mode }) => ({
  worker: {
    name: mode === "production" ? "notes-worker" : "notes-staging",
    compatibilityDate: "2026-09-29",
    entrypoint: "./src/index.ts",
    env: {
      DB: bindings.d1({
        name: mode === "production" ? "notes-prod" : "notes-staging",
      }),
    },
  },
}));

This example chooses the staging branch whenever the mode is not exactly production. Always pass the intended mode and inspect the build result; do not assume the CLI’s default mode is production.

Support for forwarding --mode also depends on the build integration. The Nuxt mode error documents one current limitation.

Stateful exports need their own declaration

A Durable Object binding points at an exported class. It does not, by itself, declare that class’s storage or lifecycle. The new worker.exports map describes that state. See the Durable Objects example before converting an existing migration history.

Common mistakes

  • Using main instead of the new entrypoint field.
  • Placing Wrangler arrays such as d1_databases directly under worker.
  • Supplying a KV namespace title where the helper requires its ID.
  • Assuming a valid TypeScript object proves the referenced resource exists.
  • Putting plaintext secrets in an executable config that a build may serialize.

The examples are checked against the installed SDK types. Resource provisioning and remote deployment still require separate validation in your account.

Sources & verification

Cloudflare configuration types and helperscf CLI source and READMECloudflare config public API