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.
Start with a Worker
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
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
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
maininstead of the newentrypointfield. - Placing Wrangler arrays such as
d1_databasesdirectly underworker. - 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.