You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Wiring a binding's config block + Env field (+ class & migrations for DO/Workflow) by hand is the core daily friction in a Cloudflare Worker workspace — exactly where an Nx generator shines. This PR adds nx g @naxodev/nx-cloudflare:binding --type=kv|r2|d1|do|queue|workflow|service, which edits wrangler.jsonc, stubs the required code (DO/Workflow classes, queue consumer, [[migrations]]), emits a matching test, and refreshes wrangler types.
24 unit tests covering all types, validation, idempotency, callbacks.
packages/nx-cloudflare-e2e/src/binding.spec.ts
3 e2e tests (KV, DO, Queue) against the published tarball.
Why
Adding a KV namespace or Durable Object to a Worker today means: hand-edit wrangler.jsonc (careful not to break the comments), look up the wrangler config schema for the right key shape, write the DO class + migration, add a queue() handler if it's a queue, re-run wrangler types to refresh Env, and write a test. That's 5–6 manual steps per binding, repeated for every binding on every Worker.
Before
After
KV/R2/D1 binding
Hand-edit JSONC + look up schema
nx g binding --type=kv --binding=MY_KV --id=...
Durable Object
Hand-edit config + write class + add migration + re-export
nx g binding --type=do --binding=MY_DO --name=MyDurableObject
Queue
Hand-edit producers + consumers + write handler
nx g binding --type=queue --binding=MY_QUEUE --name=my-queue
Env types
Manual wrangler types rerun
Auto-runs in the generator callback
Provisioning
Separate wrangler kv namespace create + copy ID
--create provisions and fills the ID automatically
How
JSONC editing.wrangler-config.ts wraps jsonc-parser's modify/applyEdits to append entries to nested arrays (kv_namespaces[], durable_objects.bindings[], queues.producers[], etc.) while preserving comments and formatting. The existing retargetWranglerSchema used regex string-replace for the $schema line — that approach doesn't scale to structured array appends.
Type-aware stubs. DO and Workflow classes land in src/<kebab-name>.ts and are re-exported from src/index.ts (Wrangler requires export from the main entrypoint). Queue consumers get a queue(batch, env) method injected into the existing export default { ... } object via bracket-matching. KV/R2/D1/Service are config-only — Env typing comes from wrangler types.
DO migrations. The generator counts existing migrations[] entries and writes tag: "v{N+1}" with new_sqlite_classes: [ClassName].
--create provisioning. The generator writes a __PENDING_CREATE__ sentinel into the config. The GeneratorCallback (post-flush) shells out to wrangler kv namespace create / r2 bucket create / d1 create / queues create, captures the real ID, and replaces the sentinel on the real filesystem. On failure: warns and leaves the placeholder for manual fill-in.
Typegen. The callback auto-runs wrangler types via execFileSync so Env picks up the new binding. --skipTypegen opts out.
Reviewer notes
jsonc-parser is a new direct dependency. It was already transitively present (via jsonc-eslint-parser). Added as a direct dependency with a loose ^3.3.0 range since it's runtime code in the published package. updateJson from @nx/devkit is strict-JSON and strips comments — not viable for JSONC.
TOML is rejected, not supported. The inference plugin accepts .toml, but TOML array-of-tables editing needs a separate parser. The generator errors with a pointer to convert to .jsonc first. Covering .toml would double the editor surface for v1.
--create only for KV/R2/D1/Queue. DO/Workflow are code classes (no remote resource), Service is a reference to another Worker. Passing --create with those types errors explicitly.
Queue handler injection uses bracket-counting, not ts-morph. The existing src/index.ts from C3 ships export default { async fetch(...) {} }. The generator finds the matching closing brace and inserts before it. If no default export object exists, it warns and prints the template for manual insertion.
Duplicate binding names error, never overwrite. The generator scans the target array for an existing binding/name match before appending.
No executors. All wrangler CLI calls go through the existing inferred nx:run-commands targets. The generator's GeneratorCallback calls wrangler types directly (not nx typegen) to avoid Nx daemon overhead in a post-flush callback.
Tests
24 unit tests in generator.spec.ts (mock run-wrangler-types + provisionResource): all 7 binding types, JSONC comment preservation, DO migration tag increment, queue handler injection + fetch handler preservation, duplicate detection, validation errors (missing --name, --create on non-provisionable, missing --bucketName/--databaseName, wrong project, TOML rejection), callback behavior (typegen auto-run, --skipTypegen, --create provisioning).
3 e2e tests in binding.spec.ts (real C3 scaffold + published tarball): KV with existing ID, DO with migration + class stub + re-export, Queue with producer + consumer + handler injection.
Ensure the fix-ci command is configured to always run in your CI pipeline to get automatic fixes in future runs. For more information, please see https://nx.dev/ci/features/self-healing-ci
Ensure the fix-ci command is configured to always run in your CI pipeline to get automatic fixes in future runs. For more information, please see https://nx.dev/ci/features/self-healing-ci
Ensure the fix-ci command is configured to always run in your CI pipeline to get automatic fixes in future runs. For more information, please see https://nx.dev/ci/features/self-healing-ci
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TL;DR
Wiring a binding's config block +
Envfield (+ class & migrations for DO/Workflow) by hand is the core daily friction in a Cloudflare Worker workspace — exactly where an Nx generator shines. This PR addsnx g @naxodev/nx-cloudflare:binding --type=kv|r2|d1|do|queue|workflow|service, which editswrangler.jsonc, stubs the required code (DO/Workflow classes, queue consumer,[[migrations]]), emits a matching test, and refresheswrangler types.Files to review (13, +1640 / -10):
packages/nx-cloudflare/src/generators/binding/generator.ts(start here)packages/nx-cloudflare/src/utils/wrangler-config.tsupdateJsonstrips comments.packages/nx-cloudflare/src/generators/binding/schema.jsonpackages/nx-cloudflare/src/utils/provision.ts--createcommand builders + exec wrapper for KV/R2/D1/Queue provisioning.packages/nx-cloudflare/src/utils/run-wrangler-types.tsexecFileSyncwrapper for auto-runningwrangler typespost-flush.packages/nx-cloudflare/src/generators/binding/generator.spec.tspackages/nx-cloudflare-e2e/src/binding.spec.tsWhy
Adding a KV namespace or Durable Object to a Worker today means: hand-edit
wrangler.jsonc(careful not to break the comments), look up the wrangler config schema for the right key shape, write the DO class + migration, add aqueue()handler if it's a queue, re-runwrangler typesto refreshEnv, and write a test. That's 5–6 manual steps per binding, repeated for every binding on every Worker.nx g binding --type=kv --binding=MY_KV --id=...nx g binding --type=do --binding=MY_DO --name=MyDurableObjectnx g binding --type=queue --binding=MY_QUEUE --name=my-queuewrangler typesrerunwrangler kv namespace create+ copy ID--createprovisions and fills the ID automaticallyHow
JSONC editing.
wrangler-config.tswrapsjsonc-parser'smodify/applyEditsto append entries to nested arrays (kv_namespaces[],durable_objects.bindings[],queues.producers[], etc.) while preserving comments and formatting. The existingretargetWranglerSchemaused regex string-replace for the$schemaline — that approach doesn't scale to structured array appends.Type-aware stubs. DO and Workflow classes land in
src/<kebab-name>.tsand are re-exported fromsrc/index.ts(Wrangler requiresexportfrom themainentrypoint). Queue consumers get aqueue(batch, env)method injected into the existingexport default { ... }object via bracket-matching. KV/R2/D1/Service are config-only —Envtyping comes fromwrangler types.DO migrations. The generator counts existing
migrations[]entries and writestag: "v{N+1}"withnew_sqlite_classes: [ClassName].--createprovisioning. The generator writes a__PENDING_CREATE__sentinel into the config. TheGeneratorCallback(post-flush) shells out towrangler kv namespace create/r2 bucket create/d1 create/queues create, captures the real ID, and replaces the sentinel on the real filesystem. On failure: warns and leaves the placeholder for manual fill-in.Typegen. The callback auto-runs
wrangler typesviaexecFileSyncsoEnvpicks up the new binding.--skipTypegenopts out.Reviewer notes
jsonc-parseris a new direct dependency. It was already transitively present (viajsonc-eslint-parser). Added as a directdependencywith a loose^3.3.0range since it's runtime code in the published package.updateJsonfrom@nx/devkitis strict-JSON and strips comments — not viable for JSONC.TOML is rejected, not supported. The inference plugin accepts
.toml, but TOML array-of-tables editing needs a separate parser. The generator errors with a pointer to convert to.jsoncfirst. Covering.tomlwould double the editor surface for v1.--createonly for KV/R2/D1/Queue. DO/Workflow are code classes (no remote resource), Service is a reference to another Worker. Passing--createwith those types errors explicitly.Queue handler injection uses bracket-counting, not ts-morph. The existing
src/index.tsfrom C3 shipsexport default { async fetch(...) {} }. The generator finds the matching closing brace and inserts before it. If no default export object exists, it warns and prints the template for manual insertion.Duplicate binding names error, never overwrite. The generator scans the target array for an existing
binding/namematch before appending.No executors. All wrangler CLI calls go through the existing inferred
nx:run-commandstargets. The generator'sGeneratorCallbackcallswrangler typesdirectly (notnx typegen) to avoid Nx daemon overhead in a post-flush callback.Tests
24 unit tests in
generator.spec.ts(mockrun-wrangler-types+provisionResource): all 7 binding types, JSONC comment preservation, DO migration tag increment, queue handler injection + fetch handler preservation, duplicate detection, validation errors (missing--name,--createon non-provisionable, missing--bucketName/--databaseName, wrong project, TOML rejection), callback behavior (typegen auto-run,--skipTypegen,--createprovisioning).3 e2e tests in
binding.spec.ts(real C3 scaffold + published tarball): KV with existing ID, DO with migration + class stub + re-export, Queue with producer + consumer + handler injection.Run:
bunx nx test nx-cloudflare(unit) /bunx nx e2e nx-cloudflare-e2e(e2e).Follow-up
--removeflag or aremove-bindinggeneratorLinks