Decision
The target toolchain for active Worker-backed apps and services is cf + Void. Adopt it per verified operation. Preserve existing commands and configuration until authentication, target identity, bindings and migrations, emitted artifacts and rollback parity are established. Wrangler remains for recorded gaps with an owner and removal condition. The shrink-only usage guard requires structured admission for expansion, changed Wrangler lines, or changed gap scope. This page refines the cf adoption gates in Oxc and Cloudflare adoption. A merged tooling switch is CI-verified, not production-delivered: every deploy target change still needs the gated production workflow, exact-commit evidence and the cutover checklist below.Toolchain shape
The Void SDK is not applied to native Workers. Void’s supported app types are
Void apps, meta-frameworks and static sites, so a native fetch/scheduled/Durable
Object Worker would have to be rewritten into Void’s routes and crons model. For
publication, Void’s own Cloudflare deploy converts the emitted config into a cf
Build Output and calls
cf deploy --prebuilt. Native Workers emit that format
directly, so they share Void’s publication path without its runtime layer.
The stable Vite plugin (1.64) already supports cloudflare.config.ts and Build
Output emission; the 2.0 beta is not required. Loading cloudflare.config.ts
requires Node.js (not Bun). The cf package requires Node ^22.23 || ^24.22 || ^26.12.
The cf/Void Wrangler-exit lane owns the cf@1.0.0-beta.20 pin.
Upgrade through a scoped dependency PR after checking upstream release notes and
rerunning config/output parity, credential-free artifact checks, secret handling,
settings readback fixtures and real Worker CI tests on the candidate version.
DO publication remains Wrangler until a disposable migration rehearsal and a
separate reviewed publisher change. Renovate holds cf prerelease pins via the
cf package rule in renovate.json; update this hold only with the qualified
upgrade PR. Do not float this beta pin automatically.
Operation parity matrix
Verified against cf1.0.0-beta.20 help, the cf documentation and
@cloudflare/vite-plugin 1.64.0 on 2026-10-23.
Native Worker template
Applied first to Cron Control. Each migrated Worker has:cloudflare.config.ts, generated bycf migrate --no-installand reviewed. Durable Objectmigrationsbecomeexports: { Class: exports.durableObject({ storage: 'sqlite' }) }for every live class.vite.config.tswithcloudflare({ experimental: { newConfig: { cfBuildOutput: true } } }), noconfigPath, explicit preview URL and observability/log settings, loopback dev server settings,persistStateunder a disposable directory for runtime tests (normal dev uses.cloudflare/state), and the Worker environment’sbuild.sourcemap: false(Wrangler did not upload source maps).- Scripts:
dev: vp dev(host/port invite.config.ts),build: vp build,type-check: cf workers types && tsc.cfis an exact devDependency; the app-levelwranglerdevDependency is removed. - A parity baseline in
scripts/ci/fixtures/cf-worker-parity/<app>.json, normalized from the finalwrangler.jsonc.scripts/ci/cf-worker-parity.test.mjscomparescloudflare.config.tswith it, and CI compares the emitted Build Output after the build withnode scripts/ci/cf-worker-parity.mjs apps/<app> scripts/ci/fixtures/cf-worker-parity/<app>.json. - The workflow validates, runs the runtime checks on source and on the emitted Build Output,
dry-runs
cf deploy --prebuilt, then uploads.cloudflare/outputas the exact-commit artifact. The gated deploy job downloads that artifact and publishes it without rebuilding.
@cloudflare/vite-plugin 1.x still depends on the Wrangler library internally. That is a
library dependency, not CLI usage; it disappears with plugin 2.x.
Rollback
--bypass-deployment-checks. Retained CI
artifacts (<app>-worker-<sha>) allow re-publishing an exact earlier build.
The local harness rejects .dev.vars* and .env* files in both the app root and
working directory (template .example files are allowed). Every declared secret
needs a nonempty disposable fixture. Undeclared/control-key fixtures are rejected,
and declared text vars are masked from the shell before process-env loading. It
restores the first prior environment value after startup
failure or close. cf-vite-worker.test.mjs covers both source and artifact modes
using a disposable Vite fixture; real Worker runtime acceptance remains a CI gate.
Wrangler usage guard
node scripts/ci/wrangler-usage.js prints the inventory. The guard scans tracked
files, including executables under plugins/, .agents/ and tmp/; Markdown,
text, lockfiles and binary assets are excluded. Ignored/untracked tmp/ files are
not an inventory: executable files there enter the guard only when tracked.
.md, .mdx and .txt are documentation exclusions in every directory;
commands embedded in those files need normal review, since the guard does not
parse executable documentation examples. It counts mention lines and all
Wrangler token occurrences conservatively, including comments and strings. A SHA-256
digest also covers each file’s Wrangler lines (all content for config files), so
same-count substitutions require admission. Lower or remove counts when usage falls.
An admitted record must be { "decision": "https://github.com/tutur3u/platform/pull/<id>", "reason": "<specific reviewed change>" }. New entries, growth, changed digests and
changed gap scope need a fresh record; reverting a migration follows the same rule.
CI
compares the allowlist with its base commit (HEAD^1 of the pull request merge ref)
and fails if that commit is unavailable.
Current gaps: paused-runtime (retained paused runtimes), opennext-adapter,
void-wave1-publication, pending-migration (services awaiting their parity PR)
shared-toolchain (root CLI provider, trusted-dependency and policy files) and
parity-tooling (the migration parity checker, which reads former Wrangler configs).
Service inventory
Settings preflight token permissions
The deploy token must cover the pinned account and every zone in that account. The settings snapshots require these Cloudflare API token permissions in addition to the publication permissions:
Grant zone visibility for all zones in the target account. Limiting visibility
to the expected hostname’s zone can hide unexpected routes and cannot establish
route parity. Do not grant unrelated accounts. These requirements apply to
COLAB_CLOUDFLARE_API_TOKEN and to COORDINATION_CLOUDFLARE_API_TOKEN when supplied
instead of the fallback. Keep values in GitHub secrets; never attach token values
to receipts. Actual token scope remains unverified until the bounded read-only
preflight succeeds. Missing access, truncated lists and unsupported account size
fail before publication; do not bypass that gate to deploy.
Cloudflare documents the accepted permissions for
Worker secrets,
deployments,
custom domains,
zones and
routes.
Deployment account variable
Set the non-secret Actions repository variableCLOUDFLARE_ACCOUNT_ID in
tutur3u/platform (Settings → Secrets and variables → Actions → Variables).
Use the account ID recorded in the service’s cloudflare.config.ts and parity
baseline; the deploy job checks it against the emitted artifact. One repository
variable supplies cron-control-production, devbox-control-production and
coordination-production. If any of those environments defines the same variable,
it must have the same value because the environment value takes precedence.
Missing or mismatched configuration blocks deployment. Source publication does
not provision this variable; the release owner must set it before promotion.
Cached Build Output
The root Turbobuild.outputs includes .cloudflare/output/**, including hidden
Vite metadata. Cache hits must restore the complete emitted tree before parity,
runtime and publication checks. .cloudflare/state remains outside the output
scope. cf-build-output-cache.test.mjs runs a disposable emit-only task through
an actual cache miss and hit, verifies restored bytes and execution count, and
checks the old output list as a negative control. It never compiles an app or
uses shared/remote cache credentials.
Production cutover checklist
For each service, the orchestrator verifies before promotion:- Exact-commit CI on the promoted SHA is green for the service workflow, including:
source runtime checks, emitted Build Output parity
(
cf-worker-parity.mjsprintsmatches <worker> deployment identity), emitted runtime checks, thecf deploy --prebuilt --dry-run --no-provisionstep, and the uploaded<app>-worker-<sha>artifact. - The production job publishes that artifact with
cf deploy --prebuilt(no rebuild) and the same--messageSHA. - The deploy job runs
cf-worker-settings.mjs beforebefore any publication or secret mutation, thenafterbefore recording success. It checks the pinned account, compatibility, preview URLs, observability/logs, cron schedules and declared secret names; snapshots routes/custom domains and hashes remaining settings without persisting text bindings. It captures the active deployment and version IDs (cf workers deployments list) as the rollback target. Also capturecf workers get <name>,cf workers secrets listand, with the Cloudflare API, the script’s cron schedules (/workers/scripts/<name>/schedules), routes or custom domains, andworkers.dev/preview URL state. The job captures them again after deployment and compares; unexplained changes fail the job before its success marker. Evidence is retained even on failure. This route-free pilot supports at most 20 account zones and one API list page, uses at most 28 GET requests per snapshot, and fails closed on missing read permissions, truncated results or unsupported scope. It never retries writes. The expected preview setting is explicitly true; this is unverified against current production until the preflight runs. A mismatch stops before mutation. - Production publication for Devbox Control and Coordination remains Wrangler
with their applied
v1migration metadata. A separate reviewed change must carry the rehearsal receipt before enabling cf publication. For these Workers, rehearse the first cf deploy on a disposable Worker created with the same Wrangler migration history and data, and confirm object data survives the switch toexports. Do not promote until that rehearsal passes. - Health checks pass on the canonical host, and the deployment marker records the SHA.
- If a check fails, roll back with
cf workers deployments createto the captured version, then reconcile before retrying.