Skip to content

Define experimental Cloudflare configuration with a single default export - #15713

Open
jamesopstad wants to merge 6 commits into
mainfrom
james/config-single-default-export
Open

jamesopstad wants to merge 6 commits into
mainfrom
james/config-single-default-export

Conversation

@jamesopstad

@jamesopstad jamesopstad commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Define experimental Cloudflare configuration with a single default export.

Experimental cloudflare.config.ts files now define settings and resources together in a default-exported defineConfig() call. Add a Worker under worker, add Containers to the containers array, or omit both to provide settings only.

import * as entrypoint from "./src/index.ts" with { type: "cf-worker" };

export default defineConfig({
	accountId: "...",
	complianceRegion: "public",
	worker: {
		name: "my-worker",
		compatibilityDate: "2026-09-18",
		entrypoint,
	},
});

  • Tests
    • Tests included/updated
    • Automated tests not possible - manual testing has been completed as follows:
    • Additional testing not necessary because:
  • Public documentation
    • Cloudflare docs PR(s):
    • Documentation not necessary because: experimental feature

A picture of a cute animal (not mandatory, but encouraged)

@changeset-bot

changeset-bot Bot commented Sep 18, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8291143

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 12 packages
Name Type
@cloudflare/build-output-utils Minor
@cloudflare/config Minor
@cloudflare/vite-plugin Minor
wrangler Minor
@cloudflare/autoconfig Minor
@cloudflare/vitest-plugin Minor
miniflare Minor
@cloudflare/containers-shared Patch
@cloudflare/deploy-helpers Patch
@cloudflare/pages-shared Patch
@cloudflare/remote-bindings Patch
@cloudflare/runtime-types Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Sep 18, 2026

Copy link
Copy Markdown
@cloudflare/autoconfig

npm i https://pkg.pr.new/@cloudflare/autoconfig@15713

@cloudflare/build-output-utils

npm i https://pkg.pr.new/@cloudflare/build-output-utils@15713

@cloudflare/codemods

npm i https://pkg.pr.new/@cloudflare/codemods@15713

@cloudflare/config

npm i https://pkg.pr.new/@cloudflare/config@15713

@cloudflare/containers-shared

npm i https://pkg.pr.new/@cloudflare/containers-shared@15713

create-cloudflare

npm i https://pkg.pr.new/create-cloudflare@15713

@cloudflare/deploy-helpers

npm i https://pkg.pr.new/@cloudflare/deploy-helpers@15713

@cloudflare/kv-asset-handler

npm i https://pkg.pr.new/@cloudflare/kv-asset-handler@15713

miniflare

npm i https://pkg.pr.new/miniflare@15713

@cloudflare/pages-functions

npm i https://pkg.pr.new/@cloudflare/pages-functions@15713

@cloudflare/pages-shared

npm i https://pkg.pr.new/@cloudflare/pages-shared@15713

@cloudflare/unenv-preset

npm i https://pkg.pr.new/@cloudflare/unenv-preset@15713

@cloudflare/vite-plugin

npm i https://pkg.pr.new/@cloudflare/vite-plugin@15713

@cloudflare/vitest-plugin

npm i https://pkg.pr.new/@cloudflare/vitest-plugin@15713

@cloudflare/workers-auth

npm i https://pkg.pr.new/@cloudflare/workers-auth@15713

@cloudflare/workers-editor-shared

npm i https://pkg.pr.new/@cloudflare/workers-editor-shared@15713

@cloudflare/workers-utils

npm i https://pkg.pr.new/@cloudflare/workers-utils@15713

wrangler

npm i https://pkg.pr.new/wrangler@15713

commit: 8291143

env[bindingName] = {
...binding,
worker: normalizeConfigReference(binding.worker, target, "worker"),
worker: normalizeConfigReference(binding.worker, target),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

A Container definition also has a name, so bindings.worker({ worker: container }) now resolves to a service binding for the Container name rather than failing validation. The old type discriminator prevented this; retain an equivalent Worker-shape check before converting the reference.

Suggested change
worker: normalizeConfigReference(binding.worker, target),
worker:
isRecord(target) &&
typeof target.name === "string" &&
typeof target.compatibilityDate === "string"
? target.name
: binding.worker,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This would be a type error and I think that's the right level of safety here. At runtime, providing a Container here is no different to providing an incorrect string.

@ask-bonk

ask-bonk Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

I'm Bonk, and I've done a quick review of your PR.

Consolidates experimental Cloudflare configuration into a single default export and updates downstream build/config consumers.

  1. P2: Container definitions can be silently emitted as Worker service bindings. Posted 1 inline suggestion.

github run

@jamesopstad
jamesopstad force-pushed the james/config-single-default-export branch from 75cf90c to 1cc4eeb Compare September 18, 2026 17:08
@jamesopstad
jamesopstad marked this pull request as ready for review September 18, 2026 17:08
@workers-devprod
workers-devprod requested review from a team and tpmmorris and removed request for a team September 18, 2026 17:09
@workers-devprod

Copy link
Copy Markdown
Contributor

Codeowners approval required for this PR:

  • @cloudflare/cloudchamber
  • @cloudflare/workers-kv
  • @cloudflare/wrangler
Show detailed file reviewers
  • .changeset/bright-builds-output.md: [@cloudflare/wrangler]
  • .changeset/calm-clouds-configure.md: [@cloudflare/wrangler]
  • .changeset/gentle-workers-simulate.md: [@cloudflare/wrangler]
  • fixtures/experimental-new-config/cloudflare.config.ts: [@cloudflare/wrangler]
  • fixtures/experimental-new-config/worker-configuration.d.ts: [@cloudflare/wrangler]
  • fixtures/vitest-plugin-examples/new-config/cloudflare.config.ts: [@cloudflare/wrangler]
  • fixtures/vitest-plugin-examples/new-config/worker-configuration.d.ts: [@cloudflare/wrangler]
  • packages/autoconfig/src/frameworks/framework-class.ts: [@cloudflare/wrangler]
  • packages/autoconfig/src/run.ts: [@cloudflare/wrangler]
  • packages/autoconfig/src/types.ts: [@cloudflare/wrangler]
  • packages/autoconfig/tests/run-summary.test.ts: [@cloudflare/wrangler]
  • packages/autoconfig/tests/run.test.ts: [@cloudflare/wrangler]
  • packages/build-output-utils/src/tests/paths.test.ts: [@cloudflare/wrangler]
  • packages/build-output-utils/src/tests/read.test.ts: [@cloudflare/wrangler]
  • packages/build-output-utils/src/tests/write.test.ts: [@cloudflare/wrangler]
  • packages/build-output-utils/src/errors.ts: [@cloudflare/wrangler]
  • packages/build-output-utils/src/index.ts: [@cloudflare/wrangler]
  • packages/build-output-utils/src/paths.ts: [@cloudflare/wrangler]
  • packages/build-output-utils/src/read.ts: [@cloudflare/wrangler]
  • packages/build-output-utils/src/write.ts: [@cloudflare/wrangler]
  • packages/config/src/tests/config-definition.test-d.ts: [@cloudflare/wrangler]
  • packages/config/src/tests/config-loader.test.ts: [@cloudflare/wrangler]
  • packages/config/src/tests/container-references.test-d.ts: [@cloudflare/wrangler]
  • packages/config/src/tests/convert.test.ts: [@cloudflare/wrangler]
  • packages/config/src/tests/generate.test.ts: [@cloudflare/wrangler]
  • packages/config/src/tests/load.test.ts: [@cloudflare/wrangler]
  • packages/config/src/tests/schema.test.ts: [@cloudflare/wrangler]
  • packages/config/src/tests/worker-references.test-d.ts: [@cloudflare/wrangler]
  • packages/config/src/bindings.ts: [@cloudflare/wrangler]
  • packages/config/src/config-loader.ts: [@cloudflare/wrangler]
  • packages/config/src/container-definition.ts: [@cloudflare/wrangler]
  • packages/config/src/convert.ts: [@cloudflare/wrangler]
  • packages/config/src/definition.ts: [@cloudflare/wrangler]
  • packages/config/src/exports.ts: [@cloudflare/wrangler]
  • packages/config/src/generate.ts: [@cloudflare/wrangler]
  • packages/config/src/index.ts: [@cloudflare/wrangler]
  • packages/config/src/inference.ts: [@cloudflare/wrangler]
  • packages/config/src/load.ts: [@cloudflare/wrangler]
  • packages/config/src/public.ts: [@cloudflare/wrangler]
  • packages/config/src/schema.ts: [@cloudflare/wrangler]
  • packages/config/src/settings-definition.ts: [@cloudflare/wrangler]
  • packages/config/src/triggers.ts: [@cloudflare/wrangler]
  • packages/config/src/types.ts: [@cloudflare/wrangler]
  • packages/config/src/worker-definition.ts: [@cloudflare/wrangler]
  • packages/containers-shared/src/build-output.ts: [@cloudflare/cloudchamber @cloudflare/wrangler]
  • packages/containers-shared/tests/build-output.test.ts: [@cloudflare/cloudchamber @cloudflare/wrangler]
  • packages/deploy-helpers/src/preview/preview.ts: [@cloudflare/wrangler]
  • packages/deploy-helpers/tests/preview-build-output.test.ts: [@cloudflare/wrangler]
  • packages/miniflare/src/config/v4-convert.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/cf.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/config/schema.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/config/v4-convert.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/dev-registry.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/logs.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/assets/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/browser/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/cache/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/core/access.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/core/cf-image.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/core/errors/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/core/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/core/inspector-proxy/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/core/modules.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/core/observability.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/core/proxy/client.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/d1/test.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/do/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/email/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/flagship/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/hello-world/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/hyperdrive/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/hyperdrive/proxy.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/images/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/images/transform.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/kv/index.spec.ts: [@cloudflare/workers-kv @cloudflare/wrangler]
  • packages/miniflare/test/plugins/kv/sites.spec.ts: [@cloudflare/workers-kv @cloudflare/wrangler]
  • packages/miniflare/test/plugins/local-explorer/aggregation.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/local-explorer/binding-map.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/local-explorer/d1.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/local-explorer/do-wrapper.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/local-explorer/do.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/local-explorer/email.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/local-explorer/helpers.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/local-explorer/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/local-explorer/kv.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/local-explorer/observability.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/local-explorer/r2.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/pipelines/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/queues/cross-process.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/queues/delay.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/queues/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/queues/retry.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/r2/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/r2/public.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/r2/s3.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/ratelimit/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/secret-store/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/shared/remote-bindings-access-warning.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/shared/remote-bindings-connect.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/shared/remote-bindings-proxy-client.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/stream/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/unsafe/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/version-metadata/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/plugins/workflows/index.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/shared/blob.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/storage-owner.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/teardown-lifecycle.spec.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/test-shared/miniflare.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/test-shared/worker-test.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/playground/additional-modules/cloudflare.config.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/playground/assets/cloudflare.config.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/playground/experimental-build-output/tests/build-output.spec.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/playground/experimental-build-output/cloudflare.config.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/playground/experimental-build-output/worker-configuration.d.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/playground/experimental-config/cloudflare.config.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/playground/experimental-config/worker-configuration.d.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/playground/static-mpa/cloudflare.config.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/src/tests/build-output-containers.spec.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/src/tests/cloudflare-environment.spec.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/src/tests/experimental-new-config.spec.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/src/tests/websockets.spec.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/src/build-output-containers.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/src/build-output-preview.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/src/plugin-config.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/src/plugins/build-output.ts: [@cloudflare/wrangler]
  • packages/vitest-plugin/AGENTS.md: [@cloudflare/wrangler]
  • packages/vitest-plugin/src/pool/new-config.ts: [@cloudflare/wrangler]
  • packages/vitest-plugin/test/new-config.test.ts: [@cloudflare/wrangler]
  • packages/wrangler/e2e/remote-binding/miniflare-remote-resources.test.ts: [@cloudflare/wrangler]
  • packages/wrangler/e2e/remote-binding/remote-bindings-api.test.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/tests/build-output.test.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/tests/cf-wrangler/build.test.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/tests/experimental-config/load.test.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/tests/helpers/mock-new-config.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/build/index.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/build/write-build-output.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/cf-wrangler/build.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/deployment-bundle/build-output.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/experimental-config.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/experimental-config/load.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/experimental-config/types.ts: [@cloudflare/wrangler]

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

Devin Review found 1 potential issue.

Devin Review

Comment on lines +50 to 52
return isRecord(resolved) && typeof resolved.name === "string"
? resolved.name
: reference;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Invalid references become Worker names

When binding.worker resolves to any named object, normalizeConfigReference converts it into a Worker name. The binding then passes schema validation and targets a nonexistent Worker.

Learn more

Cross-Worker bindings accept either a Worker name or a Worker definition. The resolver currently treats every resolved object with a string name as a Worker, without checking the remaining Worker shape. This includes Container definitions and arbitrary objects. The resulting string satisfies WorkerBindingSchema, so later parsing cannot detect the wrong resource type.

Example: A JavaScript config passes { name: "jobs", image: { reference: "registry/app" } } as bindings.worker({ worker: container }). Resolution changes the object to "jobs". Configuration parsing succeeds, but deployment creates a service binding to a Worker named jobs rather than rejecting the Container reference.

Recommended fix: Validate the resolved target with InputWorkerSchema before replacing it with target.name. Preserve invalid targets so the binding schema reports them, or add a targeted issue explaining that worker did not resolve to a Worker definition.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@jamesopstad
jamesopstad force-pushed the james/config-single-default-export branch from 1cc4eeb to 159937e Compare September 18, 2026 18:22

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

Devin Review found 2 new potential issues.

Devin Review

Comment thread packages/containers-shared/src/build-output.ts
Comment thread packages/build-output-utils/src/read.ts
devin-ai-integration[bot]

This comment was marked as resolved.

@jamesopstad
jamesopstad force-pushed the james/config-single-default-export branch from 4ae55ee to af76148 Compare September 18, 2026 19:55
devin-ai-integration[bot]

This comment was marked as resolved.

@jamesopstad
jamesopstad force-pushed the james/config-single-default-export branch from af76148 to 5ee549a Compare September 18, 2026 20:14
devin-ai-integration[bot]

This comment was marked as resolved.

@jamesopstad
jamesopstad force-pushed the james/config-single-default-export branch from 5ee549a to 8291143 Compare September 18, 2026 20:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Untriaged

Development

Successfully merging this pull request may close these issues.

2 participants