DEV Community

Shawn Bure
Shawn Bure

Posted on Originally published at elm.chat

Fixing Deploy to Cloudflare in a monorepo: expose the root contract

Disclosure: I created elm.chat. AI tools substantially assisted drafting and implementation under my direction; I reviewed the code, tests, sources, and claims and remain responsible for the result. The project is early-stage and has not had an independent security audit.

A deploy badge can look correct while every new user reaches No Wrangler
configuration detected
. In a workspace repository, the fix is to make the
target root a complete deployment contract.

The failure appears after the badge works

elm.chat already had a working production deployment and a valid Deploy to
Cloudflare link. Its Wrangler configuration lived under workers/api, where
local and production commands could find it. A new visitor followed the badge,
however, and Cloudflare reported No Wrangler configuration detected before
falling back to automatic project configuration.

That is the dangerous version of a deployment bug: maintainers can keep
shipping while the public self-host path is broken. The badge tests only
navigation. It does not prove that the target directory exposes everything the
setup flow needs.

The target directory is the contract boundary

Cloudflare analyzes the directory named by the deploy URL. If the URL targets
the repository root, nested workspace configuration is not a substitute for a
root deploy contract. The root needs a Wrangler configuration plus build and
deploy scripts that work from that directory.

{
  "scripts": {
    "build": "npm run build --workspace @example/web && npm run build --workspace @example/api",
    "deploy": "npm run build && wrangler deploy -c wrangler.jsonc"
  }
}
Enter fullscreen mode Exit fullscreen mode

The root scripts can delegate to workspaces. What matters is that a stranger—and
Cloudflare's project analysis—can start at the target root without knowing the
repository's internal layout.

Keep the public template smaller than production when necessary

elm.chat's production Worker uses an optional Analytics Engine binding for its
own aggregate growth measurement. Cloudflare does not list Analytics Engine
among the resources its deploy button automatically provisions, so the public
root template omits that binding. Independent instances work without sending
elm.chat measurement events.

Do not copy every production binding into a one-click template by reflex.
Include only resources the platform can provision or the deployer can supply
during setup. Otherwise the button turns an optional integration into a
first-run failure.

Two configurations require a drift test

A root template and a workspace production configuration can quietly diverge.
elm.chat runs a repository check that compares the Worker entry point, Durable
Object binding, migration tag, assets directory, compatibility date, and
resolved paths. The build fails if the shared runtime contract drifts.

This keeps intentional differences explicit: production can retain an optional
binding, while the independently deployable root template stays minimal and
reproducible.

Test the public journey, not the maintainer journey

  1. Open the public repository as a visitor would.
  2. Follow the published deploy button rather than a private dashboard shortcut.
  3. Select an account and wait for repository analysis.
  4. Confirm the detected build command, deploy command, and root path.
  5. Stop and investigate if the fallback warning appears.
  6. Run both root and workspace Wrangler dry runs in continuous integration.

Cloudflare documents the supported button format, scripts, and provisioned
resources in its Deploy to Cloudflare
guide
.
The elm.chat repair is public in pull request
89
, including its root
configuration and parity check.

The reusable lesson

A one-click deploy feature is an external API. Its callers do not share the
maintainer's working directory, cached settings, or mental model. Treat the
target root as a stable interface, make every dependency visible there, and
test it from the outside.


elm.chat is an open-source disposable messenger and an inspectable case study,
not an independently audited security product. Message authentication and
replay/duplicate protection remain unfinished. The hosted Cloudflare relay can
observe ordinary connection metadata, and participant devices can retain
anything they receive. It is not positioned for anonymous, high-risk, or
regulated communication.

Originally published at https://elm.chat/cloudflare-deploy-button-monorepo on August 5, 2026.

Top comments (0)