Skip to content

add containers build to build output - #15609

Open
emily-shen wants to merge 2 commits into
mainfrom
emily/build-containers
Open

add containers build to build output#15609
emily-shen wants to merge 2 commits into
mainfrom
emily/build-containers

Conversation

@emily-shen

@emily-shen emily-shen commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

This adds container building to the container to vite build and wrangler build when using the build output spec.

Note that this does not wire in any consumers of the build output - the only consumer i'm going to try to wire in is cf deploy (and versions upload), which will be happening in the cf repo. So for example this does not wire in the new config into local dev/vite preview.

We discussed adding a skip container build option as well but i haven't implemented that

@jamesopstad i wasn't sure how you wanted the container stuff to be structured in the parsed output so feel free to change it

NOTE: this doesn't fully work e2e yet!
Currently this PR does not get convertToWranglerConfig() to populate the containers field from the programmatic container config, but we need it to for validation to pass.


  • 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:

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

@emily-shen
emily-shen added this pull request to stack #15545 September 11, 2026 15:26
@changeset-bot

changeset-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d4ad323

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

This PR includes changesets to release 6 packages
Name Type
@cloudflare/containers-shared Patch
@cloudflare/vite-plugin Minor
wrangler Minor
@cloudflare/deploy-helpers Patch
@cloudflare/vitest-plugin Patch
@cloudflare/remote-bindings 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

builtImages
),
};
}

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.

BaseContainerSchema accepts any non-empty application name, so valid standard configs such as name: "Session Container" produce the tag session container:..., which Docker rejects. Durable Object images already sanitize this same input.

Suggested change
}
sanitizeRepositoryName(config.name),

@ask-bonk

ask-bonk Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

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

Adds Container image builds to experimental Build Output.

  1. P1: Posted 1 inline suggestion.

github run

@pkg-pr-new

pkg-pr-new Bot commented Sep 11, 2026

Copy link
Copy Markdown
@cloudflare/autoconfig

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

@cloudflare/build-output-utils

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

@cloudflare/codemods

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

@cloudflare/config

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

@cloudflare/containers-shared

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

create-cloudflare

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

@cloudflare/deploy-helpers

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

@cloudflare/kv-asset-handler

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

miniflare

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

@cloudflare/pages-functions

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

@cloudflare/pages-shared

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

@cloudflare/unenv-preset

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

@cloudflare/vite-plugin

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

@cloudflare/vitest-plugin

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

@cloudflare/workers-auth

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

@cloudflare/workers-editor-shared

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

@cloudflare/workers-utils

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

wrangler

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

commit: d4ad323

@jamesopstad
jamesopstad force-pushed the emily/build-containers branch from befd9e5 to 80cd82e Compare September 11, 2026 15:36
@emily-shen
emily-shen force-pushed the emily/build-containers branch from 80cd82e to 61c24d0 Compare September 11, 2026 17:08
Base automatically changed from emily/container-config-cleanup to main September 11, 2026 17:09
@emily-shen
emily-shen force-pushed the emily/build-containers branch 3 times, most recently from c8cdb48 to ef1ca3c Compare September 11, 2026 18:36
@emily-shen
emily-shen force-pushed the emily/build-containers branch from ef1ca3c to cf98b7b Compare September 12, 2026 11:47
@emily-shen
emily-shen marked this pull request as ready for review September 12, 2026 11:47
@workers-devprod
workers-devprod requested review from a team and NuroDev and removed request for a team September 12, 2026 11:48
@workers-devprod

workers-devprod commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Codeowners approval required for this PR:

  • @cloudflare/cloudchamber
  • @cloudflare/wrangler
Show detailed file reviewers
  • .changeset/build-output-containers.md: [@cloudflare/wrangler]
  • packages/config/src/config-loader.ts: [@cloudflare/wrangler]
  • packages/config/src/index.ts: [@cloudflare/wrangler]
  • packages/containers-shared/index.ts: [@cloudflare/cloudchamber @cloudflare/wrangler]
  • packages/containers-shared/package.json: [@cloudflare/cloudchamber @cloudflare/wrangler]
  • packages/containers-shared/src/build-output.ts: [@cloudflare/cloudchamber @cloudflare/wrangler]
  • packages/containers-shared/src/build.ts: [@cloudflare/cloudchamber @cloudflare/wrangler]
  • packages/containers-shared/tests/build-and-push.test.ts: [@cloudflare/cloudchamber @cloudflare/wrangler]
  • packages/containers-shared/tests/build-output.test.ts: [@cloudflare/cloudchamber @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/src/tests/build-output-containers.spec.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/src/tests/experimental-new-config.spec.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/src/build-output-containers.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/src/build.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/src/plugin-config.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/src/plugins/config.ts: [@cloudflare/wrangler]
  • packages/vite-plugin-cloudflare/src/workers-configs.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/tests/containers/deploy.test.ts: [@cloudflare/cloudchamber @cloudflare/wrangler]
  • packages/wrangler/src/tests/deployment-bundle/build-container-images.test.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/tests/experimental-config/load.test.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/api/startDevWorker/ConfigController.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/build/run-build-output.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/config/index.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/deployment-bundle/build-container-images.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/experimental-config/load.ts: [@cloudflare/wrangler]
  • pnpm-lock.yaml: [@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 2 potential issues.

1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

Comment on lines +138 to +139
builtImages.push({ localTag });
return { localReference: localTag };

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.

🔴 Repeated builds leak Docker images

Each successful buildAndWriteContainerOutput creates fresh local tags without removing tags referenced by the previous output. Rebuilding overwrites those references, leaving unreachable images that consume Docker disk indefinitely.

Learn more

A local reference is the Docker tag written into the build output for a later deployment. Each Dockerfile build creates a UUID-tagged image, and successful calls intentionally retain it. A later build writes new references into the same Container config paths, but no code reads and removes the superseded tags. Those old images can no longer be reached through the current build output and accumulate on every rebuild.

Example: Build a project containing a 2 GB Dockerfile-backed Container ten times before deployment. The output references only the tenth tag, while Docker retains all ten images and their unique tags.

Recommended fix: Before replacing Container output, read its existing localReference values and remove only tags superseded by a completed build. Preserve the previous output and tags until the new Container configs are written successfully, so a failed rebuild does not destroy the last usable output.

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.

This is not ideal, but not as big of a deal as devin is making it out to be, since docker is clever about how it stores images. also, the happy path involves a deployment which will remove the tag. but yes ideally i guess we should use docker to remove the image tag from the last build at the start, just like how we delete the built worker files in the build output directory

Comment thread .changeset/build-output-containers.md
@emily-shen
emily-shen requested review from jamesopstad and removed request for NuroDev September 12, 2026 12:11

@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.

Devin Review found 1 new potential issue.

Devin Review

const rawConfig: RawConfig = convertToWranglerConfig(
worker,
settings,
Object.values(getContainerConfigExports(result.data))

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.

🔴 Durable Object Containers abort Vite

A Durable Object-managed Container makes convertToWranglerConfig throw during plugin resolution. Vite never reaches the supported container build-output phase.

Learn more

The validated project config accepts Durable Object-managed Containers, and buildAndWriteContainerOutput explicitly builds their named images. Passing every Container export into convertToWranglerConfig() also passes this valid variant, but convertContainer unconditionally throws for it. This happens while resolving plugin configuration, before the Build Output hook runs.

Example: A default Worker plus defineContainer({ name: "app", schedulingPolicy: "durable-object", images: { web: { dockerfile: "./Dockerfile" } } }) fails during resolvePluginConfig(). The expected build would emit the named web image under the Container's Build Output directory.

Recommended fix: Keep Durable Object-managed Containers out of the Wrangler config conversion, or extend convertToWranglerConfig() to produce their supported Wrangler shape, including the linked Durable Object class and named images. Preserve all Container exports in parsedNewConfig so buildOutputContainers() still emits them.

Devin Review

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

@petebacondarwin petebacondarwin added this to the Birthday Week 2026 milestone Sep 14, 2026
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.

3 participants