@go-to-k/cdkd 0.158.0 → 0.159.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,35 +1,18 @@
1
1
  # cdkd (CDK Direct)
2
2
 
3
- Drop-in CDK CLI for existing CDK apps — faster deploys via AWS SDK instead of CloudFormation, with local emulation for Lambda, API Gateway, and ECS.
3
+ Drop-in CDK CLI for existing CDK apps — faster deploys via AWS SDK instead of CloudFormation, plus local emulation for Lambda, API Gateway, and ECS.
4
4
 
5
5
  - **Drop-in CDK compatible** — your existing CDK app code runs as-is.
6
6
  - **Up to 15x faster deploys than the AWS CDK CLI (CloudFormation)**
7
- - **Local dev for CDK apps** — invoke Lambdas, serve API Gateway routes, and run ECS tasks and services directly from your CDK code, no `cdk synth → sam local` round-trip.
7
+ - **Local dev for any CDK app** — invoke Lambdas, serve API Gateway routes, run ECS tasks/services directly from your CDK code. Works against both `cdkd deploy`-managed AND `cdk deploy`-managed (CloudFormation) stacks via `--from-state` / `--from-cfn-stack` — no migration, no `cdk synth → sam local` round-trip.
8
8
 
9
9
  ![cdk deploy vs cdkd deploy — side-by-side, 35s recording, real AWS deploy. cdkd finishes while cdk is still creating its CloudFormation changeset.](assets/cdk-vs-cdkd.gif)
10
10
 
11
- **cdkd complements the AWS CDK CLI rather than replacing it.** Use cdkd in dev/test for rapid iteration and SAM-style local execution; use the AWS CDK CLI in production for full CloudFormation tooling. Bidirectional migration is supported — [import an existing CloudFormation stack](#importing-existing-resources) into cdkd for iteration, or [export back to CloudFormation](#exporting-a-stack-back-to-cloudformation) when ready for production.
11
+ **cdkd complements the AWS CDK CLI rather than replacing it.** Use cdkd in dev/test for rapid iteration and SAM-style local execution; use the AWS CDK CLI in production for full CloudFormation tooling. Install cdkd alongside an existing `cdk deploy` workflow — no migration needed, `cdkd local *` reads deployed state directly via `--from-cfn-stack`. Bidirectional migration is also supported — [import](#importing-existing-resources) into cdkd or [export](#exporting-a-stack-back-to-cloudformation) back to CloudFormation when ready.
12
12
 
13
13
  > [!IMPORTANT]
14
14
  > cdkd is for dev/test workflows only — early in development, not yet production-ready.
15
15
 
16
- ## Features
17
-
18
- - **Synthesis orchestration**: CDK app subprocess execution, Cloud Assembly parsing, context provider loop
19
- - **Asset handling**: Self-implemented asset publisher for S3 file assets (ZIP packaging) and Docker images (ECR)
20
- - **Context resolution**: Self-implemented context provider loop for Vpc.fromLookup(), AZ, SSM, HostedZone, etc.
21
- - **Hybrid provisioning**: SDK Providers for fast direct API calls, Cloud Control API fallback for broad resource coverage
22
- - **Diff calculation**: Self-implemented resource/property-level diff between desired template and current state
23
- - **S3-based state management**: No DynamoDB required, uses S3 conditional writes for locking
24
- - **DAG-based parallelization**: Analyze `Ref`/`Fn::GetAtt` dependencies and execute in parallel
25
- - **Rollback on failure**: When a deploy errors mid-stack, cdkd rolls back the resources it just created so the stack state stays consistent (CloudFormation parity — but cdkd does this without round-tripping through CFn). Pass `cdkd deploy --no-rollback` to skip rollback and keep the partial state for Terraform-style inspection / repair. See [Rollback behavior](#rollback-behavior).
26
- - **`--no-wait` for async resources**: Skip the multi-minute wait on CloudFront / RDS / ElastiCache / NAT Gateway and return as soon as the create call returns (CloudFormation always blocks)
27
- - **VPC route DependsOn relaxation (on by default)**: Drop CDK-injected defensive `DependsOn` edges from VPC Lambdas onto private-subnet routes so `CloudFront::Distribution` and `Lambda::Url` start their ~3-min propagation in parallel with NAT Gateway stabilization (~50% faster on VPC + Lambda + CloudFront stacks). Pass `--no-aggressive-vpc-parallel` to opt out.
28
- - **Local execution without deploying** (`cdkd local invoke` / `cdkd local start-api` / `cdkd local run-task` / `cdkd local start-service`): run any Lambda — stand up every API Gateway route as a local HTTP server — start every container in an `AWS::ECS::TaskDefinition` on a per-task docker network with the AWS-published metadata-endpoints sidecar — or boot an `AWS::ECS::Service` long-running with `DesiredCount` replicas + restart-on-exit + cross-service Service Connect / Cloud Map DNS discovery (boot multiple services in one invocation, peer containers reach each other by `<discoveryName>.<namespace>` / bare alias via docker `--add-host` overlay from an in-process Cloud Map registry). SAM-compatible mental model but reuses cdkd's synthesis / asset / route-discovery (no `template.yaml` round-trip). All AWS Lambda runtimes (Node.js / Python / Ruby / Java / .NET / `provided.*`) and one server per discovered API (HTTP API v2 / REST v1 / Function URL) with their own port / authorizers / CORS configs. `local start-service` covers the long-running counterpart of `run-task` (ECS Services with DesiredCount replicas); local load-balancer emulation and `--watch` hot-reload are tracked as follow-ups. `cdkd local run-task --from-state` (also honored by `local start-service`) substitutes intrinsic-valued container `Environment[].Value` (`Ref` / `Fn::GetAtt` / `Fn::Sub` / `Fn::Join` / `Fn::ImportValue` / `Fn::GetStackOutput`) and `Secrets[].ValueFrom` against the deployed cdkd state — `table.tableName` / `ecs.Secret.fromSecretsManager(secret)` / `ecs.Secret.fromSsmParameter(param)` / cross-stack output refs Just Work locally instead of silently dropping.
29
- - **Bidirectional CloudFormation migration**: `cdkd import` adopts AWS-deployed resources (including `cdk deploy`-managed CloudFormation stacks via `--migrate-from-cloudformation`) into cdkd state without re-creating them; `cdkd export` hands a cdkd-managed stack back to CloudFormation when you're ready to move to production. See [Importing existing resources](#importing-existing-resources) and [Exporting a stack back to CloudFormation](#exporting-a-stack-back-to-cloudformation).
30
-
31
- > **Note**: Resource types not covered by either SDK Providers or Cloud Control API cannot be deployed with cdkd. If you encounter an unsupported resource type, deployment will fail with a clear error message.
32
-
33
16
  ## Benchmark
34
17
 
35
18
  **cdkd deploys up to 15x faster than AWS CDK (CloudFormation)** on SDK-Provider-handled stacks; the per-stack speedup widens with size and parallelism, and drops to ~1.5-3x on stacks dominated by Cloud Control API fallback resources.
@@ -64,6 +47,23 @@ Stack: SSM Document × 3 + Athena WorkGroup × 2 (no SDK provider — CC API fal
64
47
 
65
48
  Reproduce the first two with `./tests/benchmark/run-benchmark.sh all`. See [tests/benchmark/README.md](tests/benchmark/README.md) for details.
66
49
 
50
+ ## Features
51
+
52
+ - **Synthesis orchestration**: CDK app subprocess execution, Cloud Assembly parsing, context provider loop
53
+ - **Asset handling**: Self-implemented asset publisher for S3 file assets (ZIP packaging) and Docker images (ECR)
54
+ - **Context resolution**: Self-implemented context provider loop for Vpc.fromLookup(), AZ, SSM, HostedZone, etc.
55
+ - **Hybrid provisioning**: SDK Providers for fast direct API calls, Cloud Control API fallback for broad resource coverage
56
+ - **Diff calculation**: Self-implemented resource/property-level diff between desired template and current state
57
+ - **S3-based state management**: No DynamoDB required, uses S3 conditional writes for locking
58
+ - **DAG-based parallelization**: Analyze `Ref`/`Fn::GetAtt` dependencies and execute in parallel
59
+ - **Rollback on failure**: When a deploy errors mid-stack, cdkd rolls back the resources it just created so the stack state stays consistent (CloudFormation parity — but cdkd does this without round-tripping through CFn). Pass `cdkd deploy --no-rollback` to skip rollback and keep the partial state for Terraform-style inspection / repair. See [Rollback behavior](#rollback-behavior).
60
+ - **`--no-wait` for async resources**: Skip the multi-minute wait on CloudFront / RDS / ElastiCache / NAT Gateway and return as soon as the create call returns (CloudFormation always blocks)
61
+ - **VPC route DependsOn relaxation (on by default)**: Drop CDK-injected defensive `DependsOn` edges from VPC Lambdas onto private-subnet routes so `CloudFront::Distribution` and `Lambda::Url` start their ~3-min propagation in parallel with NAT Gateway stabilization (~50% faster on VPC + Lambda + CloudFront stacks). Pass `--no-aggressive-vpc-parallel` to opt out.
62
+ - **Local execution** (`cdkd local invoke` / `start-api` / `run-task` / `start-service`): run Lambdas, API Gateway routes, ECS tasks and long-running ECS services from your CDK code via Docker. All AWS Lambda runtimes, container Lambdas, REST v1 / HTTP v2 / Function URL routes, Service Connect / Cloud Map. Works for both `cdkd deploy`-managed (`--from-state`) AND `cdk deploy`-managed (`--from-cfn-stack`) stacks. See [Local execution](#local-execution).
63
+ - **Bidirectional CloudFormation migration**: `cdkd import --migrate-from-cloudformation` adopts existing CFn stacks (including `cdk deploy`-managed) into cdkd state without re-creating resources; `cdkd export` hands a cdkd stack back to CloudFormation when production-ready. See [Importing](#importing-existing-resources) / [Exporting](#exporting-a-stack-back-to-cloudformation).
64
+
65
+ > **Note**: Resource types not covered by either SDK Providers or Cloud Control API cannot be deployed with cdkd. Deployment fails with a clear error message naming the type + a 1-click issue link.
66
+
67
67
  ## How it works
68
68
 
69
69
  ```
@@ -159,256 +159,57 @@ cdkd has three command families:
159
159
  use them to inspect / clean up state when the source is gone or
160
160
  you don't want to synth. `cdkd state destroy` is the CDK-app-free
161
161
  counterpart of `cdkd destroy`.
162
- - **`cdkd local ...` subcommands** (`local invoke`, `local start-api`,
163
- `local run-task`, `local start-service`) run synthesized workloads
164
- locally inside Docker containers. The Lambda variants (`local invoke` /
165
- `local start-api`) bundle the AWS Lambda Runtime Interface Emulator
166
- (RIE); `local invoke` runs a single Lambda once, and `local start-api`
167
- stands up a long-running HTTP server that maps API Gateway / HTTP API /
168
- Function URL routes to local Lambda invocations. `local run-task` is
169
- the ECS one-shot counterpart — it locates an
170
- `AWS::ECS::TaskDefinition` from the synthesized template and stands
171
- up every container in `dependsOn` order on a per-task docker network
172
- with the AWS-published metadata endpoints sidecar, so containers see
173
- `ECS_CONTAINER_METADATA_URI_V4` (and optionally task-role creds via
174
- `--assume-task-role`) just like they would on Fargate / ECS.
175
- `local start-service` is the long-running counterpart for
176
- `AWS::ECS::Service`: it discovers the service, chains into the same
177
- per-task machinery for each `DesiredCount` replica (clamped by
178
- `--max-tasks`), and keeps every replica running until `^C` — failed
179
- replicas restart per `--restart-policy on-failure|always|none`. It
180
- also accepts multiple service targets in one invocation
181
- (`cdkd local start-service Stack/Orders Stack/Frontend`); per-service
182
- `AWS::ServiceDiscovery::PrivateDnsNamespace` / `Service` +
183
- `ServiceConnectConfiguration` / `ServiceRegistries[]` blocks are
184
- parsed and each booted replica's container IP is published to a
185
- shared in-process Cloud Map registry, then injected into the next
186
- service's containers via docker `--add-host <fqdn>:<ip>` so
187
- `wget http://orders/` from inside the `frontend` container resolves
188
- via `/etc/hosts` to the orders replica (boot targets in
189
- producer-then-consumer order; see [docs/local-emulation.md](docs/local-emulation.md)
190
- for v1 limitations — first-wins for multi-replica routing, no SRV
191
- records, no Envoy L7). No AWS API calls beyond optional STS / Secrets
192
- resolution, no state bucket needed. Local load-balancer emulation and
193
- `--watch` hot-reload for `start-service` are deferred to follow-up
194
- PRs.
162
+ - **`cdkd local ...` subcommands** (`local invoke` / `start-api` /
163
+ `run-task` / `start-service`) run synthesized workloads locally
164
+ inside Docker containers no AWS deploy needed. Modeled on
165
+ `sam local *` but reads CDK state directly via `--from-state`
166
+ (cdkd-managed) or `--from-cfn-stack` (CFn-managed). See
167
+ [Local execution](#local-execution).
195
168
 
196
169
  Options like `--app`, `--state-bucket`, and `--context` can be omitted if configured via `cdk.json` or environment variables (`CDKD_APP`, `CDKD_STATE_BUCKET`).
197
170
 
198
171
  ```bash
199
- # Bootstrap (create S3 bucket for state)
200
- cdkd bootstrap \
201
- --state-bucket my-cdkd-state \
202
- --region us-east-1
203
-
204
- # Synthesize only
205
- cdkd synth --app "node app.ts"
206
-
207
- # List all stacks in the CDK app (alias: ls)
208
- cdkd list
209
- cdkd ls
210
- cdkd list --long # YAML records with id/name/environment
211
- cdkd list --long --json # same, but JSON
212
- cdkd list --show-dependencies # id + dependency list per stack
213
- cdkd list 'MyStage/*' # filter by display path (CDK CLI parity)
214
-
215
- # Deploy from a pre-synthesized cloud assembly directory
216
- cdkd deploy --app cdk.out
217
-
218
- # Deploy (single stack auto-detected, reads --app from cdk.json)
219
- cdkd deploy
220
-
221
- # Deploy specific stack(s)
222
- cdkd deploy MyStack
223
- cdkd deploy Stack1 Stack2
224
-
225
- # Deploy all stacks
172
+ # Synth + deploy
173
+ cdkd synth
174
+ cdkd deploy # single-stack auto-detected
175
+ cdkd deploy MyStack # by name (or 'MyStage/Api' display path)
226
176
  cdkd deploy --all
177
+ cdkd deploy --dry-run # plan only, no changes
178
+ cdkd deploy --no-rollback # Terraform-style: keep partial state on failure
179
+ cdkd deploy --no-wait # skip multi-minute waits (CloudFront / RDS / NAT)
227
180
 
228
- # Deploy with wildcard (matched against the physical CloudFormation stack name)
229
- cdkd deploy 'My*'
230
-
231
- # Deploy stacks under a CDK Stage using the hierarchical path (CDK CLI parity)
232
- # Patterns containing '/' are routed to the CDK display path; both forms work:
233
- cdkd deploy 'MyStage/*' # all stacks under MyStage
234
- cdkd deploy MyStage/Api # specific stack by display path
235
- cdkd deploy MyStage-Api # same stack by physical CloudFormation name
236
-
237
- # Deploy with context values
238
- cdkd deploy -c env=staging -c featureFlag=true
239
-
240
- # Deploy with explicit options
241
- cdkd deploy MyStack \
242
- --app "node app.ts" \
243
- --state-bucket my-cdkd-state \
244
- --verbose
245
-
246
- # Show diff (what would change)
181
+ # Inspect what would change
247
182
  cdkd diff MyStack
248
- cdkd diff MyParent --recursive # also diff every nested-stack child vs its own state (#555 A5)
249
- cdkd diff MyParent --recursive --json # nested {stack, changes, children: [...]} JSON
250
- cdkd diff MyStack --fail # exit 1 when any change is detected (CI gate; matches cdk diff --fail)
251
-
252
- # Detect drift between cdkd state and AWS reality (state-only; no synth)
253
- # Exits 0 with no drift, 1 when drift is detected, 2 on partial revert failure.
254
- cdkd drift MyStack
255
- cdkd drift --all --json
256
-
257
- # Resolve drift: state ← AWS (catch up state with manual console changes)
258
- cdkd drift MyStack --accept --yes
259
-
260
- # Resolve drift: AWS ← state (push state values back into AWS via provider.update)
261
- cdkd drift MyStack --revert --yes
262
-
263
- # Refresh the deploy-time AWS snapshot used as drift baseline.
264
- # Optional — `cdkd deploy` itself auto-refreshes on the first deploy after
265
- # upgrading from a pre-v3 cdkd binary (= state schema `version: 2`), in
266
- # parallel with the deploy at no critical-path cost. This command is the
267
- # manual / non-deploy path: run it when you want the baseline refreshed
268
- # without redeploying (e.g. for resources that won't change in any
269
- # near-future deploy). Idempotent on the same v3 state — see "Drift
270
- # detection" below for the full upgrade story.
271
- cdkd state refresh-observed MyStack
272
-
273
- # Dry run (plan only, no changes)
274
- cdkd deploy --dry-run
275
-
276
- # Deploy with no rollback on failure (Terraform-style)
277
- cdkd deploy --no-rollback
278
-
279
- # Deploy only the specified stack (skip dependency auto-inclusion)
280
- cdkd deploy -e MyStack
281
-
282
- # Skip the multi-minute wait on async resources (CloudFront, RDS, NAT GW, etc.)
283
- cdkd deploy --no-wait
183
+ cdkd diff MyStack --fail # exit 1 on any change (CI gate)
284
184
 
285
- # Synth + build + publish assets only (no deploy) — typical CI split
286
- cdkd publish-assets
185
+ # Drift detection compare state vs AWS reality (no synth)
186
+ cdkd drift MyStack # exit 1 if drift
187
+ cdkd drift MyStack --accept --yes # state ← AWS
188
+ cdkd drift MyStack --revert --yes # AWS ← state
287
189
 
288
- # Destroy resources
190
+ # Asset / destroy / unlock
191
+ cdkd publish-assets # synth + upload only (typical CI split)
289
192
  cdkd destroy MyStack
290
- cdkd destroy --all --force
193
+ cdkd force-unlock MyStack # clear stale lock from an interrupted deploy
291
194
 
292
- # Force-unlock a stale lock from interrupted deploy
293
- cdkd force-unlock MyStack
294
-
295
- # Adopt already-deployed AWS resources into cdkd state.
296
- # See docs/import.md for the full guide (auto / selective / hybrid modes,
297
- # --resource overrides, --resource-mapping CDK CLI compatibility).
298
- cdkd import MyStack --dry-run
195
+ # Adopt existing AWS resources into cdkd state
299
196
  cdkd import MyStack --yes
300
197
 
301
- # Inspect state-bucket info on demand (bucket name, region, source, schema version, stack count).
302
- # Routine commands (deploy / destroy / etc.) no longer print the bucket banner by default
303
- # pass --verbose to surface it in their debug logs, or use this subcommand for an explicit answer.
304
- cdkd state info
305
- cdkd state info --json # JSON output for tooling
306
- cdkd state info --state-bucket my-bucket # explicit bucket; reports Source: --state-bucket flag
307
-
308
- # List stacks registered in the cdkd state bucket
309
- cdkd state list
310
- cdkd state ls --long # include resource count, last-modified, lock status
311
- cdkd state list --json # JSON output (alone, or combined with --long)
312
- cdkd state list --tree # parent → child stack tree (nested stacks; #555 A3)
313
- cdkd state list --tree --json # tree as nested JSON
314
-
315
- # List resources of a single stack from state
316
- cdkd state resources MyStack # aligned columns: LogicalID, Type, PhysicalID
317
- cdkd state resources MyStack --long # per-resource block with dependencies and attributes
318
- cdkd state resources MyStack --json # full JSON array
319
-
320
- # Show full state record for a stack (metadata, outputs, all resources incl. properties)
321
- cdkd state show MyStack
322
- cdkd state show MyStack --json # raw {state, lock} JSON
323
- cdkd state show MyParent --show-nested # recursively show every nested-stack child (#555 A4)
324
- cdkd state show MyParent --show-nested --json # tree as nested {state, lock, children: [...]} JSON
325
-
326
- # Orphan one or more RESOURCES from cdkd's state (does NOT delete AWS resources).
327
- # Per-resource, mirrors aws-cdk-cli's `cdk orphan --unstable=orphan`.
328
- # Synth-driven — needs --app / cdk.json. Construct paths use CDK's L2-style form
329
- # (`<StackName>/<Path/To/Construct>`); the synthesized `/Resource` suffix is
330
- # matched implicitly. Passing an L2 wrapper that contains multiple CFn resources
331
- # orphans every child under it (matches upstream's prefix-match semantics).
332
- cdkd orphan MyStack/MyTable # confirmation prompt (y/N)
333
- cdkd orphan MyStack/MyTable --yes
334
- cdkd orphan MyStack/MyTable MyStack/MyBucket # multiple resources, same stack
335
- cdkd orphan MyStack/MyTable --dry-run # print rewrite audit, no save
336
- cdkd orphan MyStack/MyTable --force # also fall back to cached
337
- # attributes when live fetch fails
338
-
339
- # State-driven counterpart that orphans a WHOLE STACK's state record
340
- # (no CDK app needed — works against the bucket).
341
- cdkd state orphan MyStack # confirmation prompt (y/N)
342
- cdkd state orphan MyStack --yes # skip confirmation
343
- cdkd state orphan StackA StackB --force # also bypass the locked-stack refusal
344
-
345
- # Destroy a stack's AWS resources AND remove its state record, without
346
- # requiring the CDK app (no synth — works from any working directory).
347
- cdkd state destroy MyStack # per-stack confirmation prompt
348
- cdkd state destroy MyStack OtherStack --yes
349
- cdkd state destroy --all -y # every stack in the bucket
350
- cdkd state destroy MyStack --region us-east-1
198
+ # State-bucket-only commands (no CDK app needed)
199
+ cdkd state info # bucket name, region, schema version
200
+ cdkd state list # one row per (stackName, region)
201
+ cdkd state list --tree # parent → child nested-stack tree
202
+ cdkd state show MyStack # full state record
203
+ cdkd state resources MyStack # logical id / type / physical id
204
+ cdkd state destroy MyStack # delete AWS resources + state, no CDK app
205
+ cdkd state orphan MyStack # remove state record only (AWS resources stay)
351
206
  ```
352
207
 
353
- ## Compatibility
354
-
355
- cdkd supports the standard CloudFormation surface — intrinsic functions,
356
- pseudo parameters, parameters / conditions, cross-stack / cross-region
357
- references, asset publishing, custom resources, and so on. See
358
- **[docs/supported-features.md](docs/supported-features.md)** for the
359
- full reference. For per-resource-type provisioning support (SDK Providers
360
- vs Cloud Control API fallback), see
361
- **[docs/supported-resources.md](docs/supported-resources.md)**.
362
-
363
- ### Cross-stack references — strong vs weak
364
-
365
- `Fn::ImportValue` is a **strong reference**: `cdkd destroy <producer>`
366
- refuses to delete a stack while any other stack still imports one of
367
- its exports via `Fn::ImportValue`. Matches CloudFormation's behavior.
368
- The error message names every offending consumer and points at the
369
- two valid resolution paths (destroy the consumer first, or remove
370
- the `Fn::ImportValue` from the consumer's template and redeploy).
371
-
372
- `Fn::GetStackOutput` (cdkd-specific) is a **weak reference**: the
373
- producer stays deletable independently of consumers. Use it when you
374
- intentionally want decoupled lifecycles (cross-region / cross-stage /
375
- staging environments).
376
-
377
- A persistent per-region exports index at
378
- `s3://{state-bucket}/cdkd/_index/{region}/exports.json` makes
379
- `Fn::ImportValue` resolution O(1) at scale (200-stack environments
380
- resolve in ~100ms vs minutes with the pre-#343 per-resolve scan).
381
- The index is a derived view rebuilt from `state.json` on demand —
382
- state.json remains the canonical source of truth, and strong-reference
383
- safety checks scan it directly rather than trusting the index.
384
-
385
- See **[docs/cross-stack-references.md](docs/cross-stack-references.md)**
386
- for the full design (`Fn::ImportValue` strong-reference rules added in
387
- state schema v4, lifecycle, locking, failure modes). State schema is at
388
- v5 since v0.100.0; `DeletionPolicy` / `UpdateReplacePolicy` changes
389
- between deploys are now detected and surfaced (see
390
- [docs/state-management.md](docs/state-management.md)).
391
-
392
- ## Rollback behavior
393
-
394
- When a deploy fails mid-stack (e.g. a resource hits a validation error
395
- or AWS rejects the request), cdkd by default **rolls back the
396
- already-completed resources in the same deploy** so the stack state
397
- stays consistent — every resource cdkd just created in this run is
398
- deleted in reverse dependency order, the state record is updated to
399
- match, and the CLI exits non-zero. Resources that existed before this
400
- deploy are NOT touched.
401
-
402
- Pass `cdkd deploy --no-rollback` to skip the rollback (Terraform-style:
403
- the partial state is preserved so you can `cdkd state show <stack>`,
404
- inspect what landed, fix the underlying issue, and re-run `cdkd deploy`
405
- to continue from the half-deployed state). Recommended only when you
406
- plan to manually inspect / repair; the default is safer for CI.
407
-
408
- Mid-deploy state is also saved per-resource as work completes, so even
409
- if cdkd itself crashes between the failure and the rollback, the state
410
- file accurately reflects what's on AWS and a follow-up `cdkd destroy`
411
- won't orphan anything.
208
+ See **[docs/cli-reference.md](docs/cli-reference.md)** for the full flag
209
+ matrix (`--concurrency`, `--no-aggressive-vpc-parallel`,
210
+ `--allow-unsupported-properties`, `--role-arn`, etc.), per-command details
211
+ including the synth-driven per-resource `cdkd orphan <constructPath>`
212
+ variant, and stage / wildcard pattern matching.
412
213
 
413
214
  ## `--no-wait`: skip async-resource waits
414
215
 
@@ -424,20 +225,6 @@ See [docs/cli-reference.md](docs/cli-reference.md#--no-wait-skip-async-resource-
424
225
  for per-resource caveats (NAT egress, RDS final-snapshot timing,
425
226
  etc.).
426
227
 
427
- ## VPC route DependsOn relaxation (on by default)
428
-
429
- CDK injects defensive `DependsOn` from VPC Lambdas onto private-subnet
430
- routes. The dependency is real at runtime but NOT required at deploy
431
- time. cdkd drops it by default so CloudFront + Lambda::Url propagation
432
- runs in parallel with NAT stabilization (~50% faster on VPC+Lambda+CloudFront
433
- stacks; bench-cdk-sample 398s → 181s). Pass
434
- `cdkd deploy --no-aggressive-vpc-parallel` to opt out (e.g. when a
435
- Custom Resource synchronously invokes a VPC Lambda outside cdkd's
436
- Lambda-ServiceToken Active wait).
437
-
438
- See [docs/cli-reference.md](docs/cli-reference.md) for the full
439
- type-pair allowlist and trade-off notes.
440
-
441
228
  ## Local execution
442
229
 
443
230
  The `cdkd local` family runs AWS workloads on the developer's machine
@@ -453,96 +240,85 @@ maintain, no `cdk synth | sam ...` round-trip.
453
240
  | `cdkd local run-task <target>` | ECS RunTask — every container in a task definition started on a per-task docker network |
454
241
  | `cdkd local start-service <target>` | Long-running ECS Service emulator — `DesiredCount` replicas with restart-on-exit (no local load balancer in v1) |
455
242
 
456
- Requires Docker. Pass `--from-state` to substitute deployed physical
457
- IDs into intrinsic-valued properties (`Ref` / `Fn::GetAtt` / `Fn::Sub` /
458
- `Fn::Join` against the same stack's state plus AWS pseudo parameters
459
- via STS, AND `Fn::ImportValue` / `Fn::GetStackOutput` against the
460
- persistent exports index for cross-stack references same-account /
461
- same-region); without it, intrinsic values are dropped with a per-key
462
- warning (matches `sam local *` semantics). For CDK apps deployed via
463
- the upstream CDK CLI (`cdk deploy` → CloudFormation), pass
464
- `--from-cfn-stack [<cfn-stack-name>]` instead: cdkd reads the deployed
465
- CFn stack via `DescribeStackResources` + `ListExports` and substitutes
466
- `Ref` / `Fn::ImportValue` against the same code path (`Fn::GetAtt` is
467
- warn-and-dropped in v1). Mutually exclusive with `--from-state`.
243
+ Requires Docker. Pass `--from-state` (cdkd-deployed) or
244
+ `--from-cfn-stack` (cdk-deployed / CFn-managed) to substitute deployed
245
+ physical IDs into intrinsic-valued env vars / secrets / image URIs;
246
+ without either, intrinsic values are dropped with a per-key warning
247
+ (matches `sam local *`). The two flags are mutually exclusive.
468
248
 
469
249
  ### `local invoke`
470
250
 
471
251
  ```bash
472
- cdkd local invoke MyStack/MyApi/Handler # one-shot invoke
252
+ cdkd local invoke MyStack/Handler # one-shot invoke
473
253
  cdkd local invoke MyStack/Handler --event events/get.json
474
- cdkd local invoke MyStack/Handler --from-state # cdkd-deployed: recover deployed env vars
475
- cdkd local invoke MyStack/Handler --from-cfn-stack # cdk-deployed (CFn): same flow via DescribeStackResources
254
+ cdkd local invoke MyStack/Handler --from-state # OR --from-cfn-stack
476
255
  ```
477
256
 
478
- Supports every current AWS Lambda runtime (Node.js / Python / Ruby /
479
- Java / .NET / `provided.al2023`), container Lambdas
480
- (`DockerImageFunction` / `Code.ImageUri`) via local-build or ECR pull,
481
- and same-stack Lambda Layers bind-mounted at `/opt`.
257
+ All AWS Lambda runtimes (Node.js / Python / Ruby / Java / .NET /
258
+ `provided.al2023`), ZIP and container Lambdas, same-stack Lambda Layers
259
+ bind-mounted at `/opt`.
482
260
 
483
261
  ### `local start-api`
484
262
 
485
263
  ```bash
486
- cdkd local start-api # one HTTP server per discovered API
487
- cdkd local start-api --port 3000 # pin the first server's port
488
- cdkd local start-api MyHttpApi # filter to one API (logical id, single-stack apps)
489
- cdkd local start-api MyStack/MyHttpApi # OR: CDK Construct path
490
- cdkd local start-api --warm --watch # pre-start + hot reload
491
- cdkd local start-api --from-state # substitute deployed env vars in Lambda Environment
264
+ cdkd local start-api # one HTTP server per discovered API
265
+ cdkd local start-api MyStack/MyHttpApi --watch # filter + hot reload
266
+ cdkd local start-api --from-state # OR --from-cfn-stack
492
267
  ```
493
268
 
494
- One server per discovered API authorizers, CORS configs, and stage
495
- variables stay scoped to the owning API. Supports REST v1 + HTTP API +
496
- Function URL with **AWS_PROXY** integrations AND every REST v1
497
- non-AWS_PROXY integration kind: **MOCK** (status-code selection via
498
- request template + response-template VTL), **HTTP_PROXY** (verbatim
499
- upstream forward with `RequestParameters` mappings), **HTTP**
500
- (HTTP_PROXY + bidirectional VTL), and **AWS** Lambda non-proxy
501
- (request + response VTL via the hand-rolled engine at
502
- `src/local/vtl-engine.ts`).
503
- Direct AWS-service integrations (S3 / SQS / SNS / DynamoDB / etc.) are
504
- NOT emulated — deploy to AWS or use HTTP_PROXY to a local mock instead.
505
- Authorizers: Lambda TOKEN / REQUEST, Cognito User Pool, HTTP v2 JWT
506
- (JWKS-verified), and REST v1 `AuthorizationType: 'AWS_IAM'` (SigV4
507
- signature verification only — IAM policy evaluation is not emulated;
508
- see `docs/local-emulation.md`). CORS preflight (HTTP API v2
509
- `CorsConfiguration` + REST v1 OPTIONS MOCK preflight from
510
- `defaultCorsPreflightOptions`); hot reload via `--watch`;
511
- deploy-state-backed env var substitution via `--from-state`.
512
-
513
- Function URL `InvokeMode: RESPONSE_STREAM` is supported (issue #467):
514
- streaming Lambdas are invoked via the RIE streaming protocol and the
515
- response is piped to the HTTP client with `Transfer-Encoding: chunked`.
516
- Note that AWS's local RIE buffers the response — incremental chunk
517
- delivery only manifests against the deployed Lambda runtime; locally
518
- the response shape is correct but arrives in one block.
519
-
520
- Routes whose integration cdkd cannot emulate (REST v1 AWS integration
521
- to a non-Lambda service, HTTP_PROXY / HTTP with non-literal `Uri`, HTTP
522
- API v2 service integrations, WebSocket APIs, Function URLs with IAM
523
- auth, cross-stack Lambda Arn references) **do not block boot** — the
524
- server starts with a per-route `[warn]` summary and returns HTTP 501 +
525
- the reason in the JSON body if and when the route is hit. This lets
526
- you run the rest of your API surface locally while the unsupported
527
- routes stay on the deployed API.
269
+ REST v1 + HTTP API v2 + Function URL with all integration kinds
270
+ (AWS_PROXY / MOCK / HTTP_PROXY / HTTP / AWS Lambda non-proxy via
271
+ hand-rolled VTL), authorizers (Lambda / Cognito / HTTP v2 JWT /
272
+ AWS_IAM SigV4 on REST v1 + Function URL), CORS, stage variables,
273
+ `--watch` hot reload.
528
274
 
529
275
  ### `local run-task`
530
276
 
531
277
  ```bash
532
278
  cdkd local run-task MyStack/MyService/TaskDef
533
- cdkd local run-task MyTaskDef --from-state # resolve deployed secrets / env intrinsics
279
+ cdkd local run-task MyTaskDef --from-state # OR --from-cfn-stack
534
280
  ```
535
281
 
536
- Starts every container in the task definition on a per-task docker
537
- network with the AWS-published ECS metadata sidecar
538
- (`amazon/amazon-ecs-local-container-endpoints`). `DependsOn` /
539
- `Secrets` / `Volumes` (Host / Docker) are honored; `Secrets[].ValueFrom`
540
- is resolved from SecretsManager / SSM at startup.
282
+ Every container in the task definition on a per-task docker network
283
+ with the AWS-published ECS metadata sidecar.
541
284
 
542
- See [docs/local-emulation.md](docs/local-emulation.md) for the full
543
- reference — supported runtimes, target resolution, every flag, exit
544
- codes, route precedence, container-pool semantics, networking model,
545
- v1 scope notes.
285
+ ### `local start-service`
286
+
287
+ ```bash
288
+ cdkd local start-service MyStack/Orders MyStack/Web # multiple services in one invocation
289
+ cdkd local start-service MyStack/Orders --from-state # OR --from-cfn-stack
290
+ ```
291
+
292
+ Long-running ECS Service emulator: `DesiredCount` replicas with
293
+ restart-on-exit, cross-service Service Connect / Cloud Map DNS
294
+ discovery (peer containers reach each other by `<discoveryName>.<namespace>`).
295
+ No local load-balancer in v1.
296
+
297
+ See **[docs/local-emulation.md](docs/local-emulation.md)** for the
298
+ full reference — runtimes, target resolution, every flag, integration
299
+ and authorizer detail, route precedence, container pool, networking,
300
+ `--from-cfn-stack` semantics, v1 scope.
301
+
302
+ ## Rollback behavior
303
+
304
+ When a deploy fails mid-stack (e.g. a resource hits a validation error
305
+ or AWS rejects the request), cdkd by default **rolls back the
306
+ already-completed resources in the same deploy** so the stack state
307
+ stays consistent — every resource cdkd just created in this run is
308
+ deleted in reverse dependency order, the state record is updated to
309
+ match, and the CLI exits non-zero. Resources that existed before this
310
+ deploy are NOT touched.
311
+
312
+ Pass `cdkd deploy --no-rollback` to skip the rollback (Terraform-style:
313
+ the partial state is preserved so you can `cdkd state show <stack>`,
314
+ inspect what landed, fix the underlying issue, and re-run `cdkd deploy`
315
+ to continue from the half-deployed state). Recommended only when you
316
+ plan to manually inspect / repair; the default is safer for CI.
317
+
318
+ Mid-deploy state is also saved per-resource as work completes, so even
319
+ if cdkd itself crashes between the failure and the rollback, the state
320
+ file accurately reflects what's on AWS and a follow-up `cdkd destroy`
321
+ won't orphan anything.
546
322
 
547
323
  ## Importing existing resources
548
324
 
@@ -579,63 +355,31 @@ parity matrix vs upstream `cdk import`.
579
355
  ## Exporting a stack back to CloudFormation
580
356
 
581
357
  `cdkd export` is the mirror of `cdkd import`: it hands a cdkd-managed
582
- stack over to CloudFormation via a CFn `ChangeSetType=IMPORT` changeset.
358
+ stack back to CloudFormation via a CFn `ChangeSetType=IMPORT` changeset.
583
359
  AWS resources are unchanged across the migration; cdkd state for the
584
360
  exported stack is deleted on success. From then on the stack is managed
585
- by `cdk deploy` / `aws cloudformation`.
586
-
587
- Lambda-backed Custom Resources (`Custom::*` and
588
- `AWS::CloudFormation::CustomResource`) are NOT directly CFn-importable.
589
- `cdkd export --include-non-importable` opts into a 2-phase migration
590
- to handle them: phase 1 IMPORT changeset adopts every importable
591
- resource, then phase 2 UPDATE changeset re-CREATEs the Custom Resources
592
- through CFn — which re-invokes each backing Lambda's onCreate handler.
593
- The Custom Resource Lambda must be idempotent AND must POST to
594
- `event.ResponseURL` per the cfn-response protocol. Without the flag,
595
- the command refuses to proceed and the user is expected to destroy
596
- the offending resources (or accept abandoning them) first. Nested
597
- `AWS::CloudFormation::Stack` rows are fully supported as of
598
- [#464](https://github.com/go-to-k/cdkd/issues/464) PR B2: `cdkd export`
599
- recursively walks the cdkd state tree, validates every parent → child
600
- link, and submits **IMPORT changesets per cdkd-managed stack** in
601
- leaf-first order — leaf stacks via one CREATE-via-IMPORT changeset, non-leaf
602
- parents via two changesets (Phase 1A CREATE-via-IMPORT for the parent's
603
- leaf resources only, then Phase 1B UPDATE-via-IMPORT for the just-imported
604
- child adoption per AWS's
605
- ["Nest an existing stack"](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resource-import-nested-stacks.html)
606
- pattern with `DeletionPolicy: Retain` plus
607
- `ResourceIdentifier: { StackId: <child arn> }` plus AWS-validated
608
- child-Tag forwarding). Between phases cdkd flips each
609
- stack's status from `IMPORT_COMPLETE` to `UPDATE_COMPLETE` via a no-op
610
- tag-only `UpdateStack` (AWS rejects `IMPORT_COMPLETE` as a non-importable
611
- status for nested adoption). The original "one atomic
612
- `--include-nested-stacks` IMPORT changeset" design was found infeasible
613
- by the 2026-05-24 AWS spike — AWS rejects that flag combination with
614
- `ValidationError: IncludeNestedStacks is not supported for changeSet type: IMPORT`;
615
- see [docs/design/464-nested-stacks-export-import.md](docs/design/464-nested-stacks-export-import.md)
616
- §4.0 / §4.3 for the per-stack-loop algorithm. Each child cdkd stack
617
- (`<parent>~<childLogicalId>`) becomes its own CFn stack named
618
- `<parent>-<childLogicalId>` by default (`~` is illegal in CFn stack
619
- names); override per child with `--cfn-child-stack-name '<cdkd>=<cfn>'`
620
- (repeatable). Fresh `cdkd deploy` of nested stacks works via
621
- [#459](https://github.com/go-to-k/cdkd/issues/459).
361
+ by `cdk deploy` / `aws cloudformation`. Accepts JSON and YAML templates
362
+ (shorthand intrinsics round-trip).
622
363
 
623
364
  ```bash
624
365
  cdkd export MyStack # confirmation prompt; CFn stack name = cdkd stack name
625
366
  cdkd export MyStack --cfn-stack-name MyStack-CFn
626
367
  cdkd export MyStack --dry-run # print the import plan, do not call CFn
627
- cdkd export MyStack --template path.json # skip synth, use a pre-rendered template (JSON or YAML — format auto-detected)
628
368
  cdkd export MyStack --include-non-importable # 2-phase: IMPORT importable + CFn-CREATE Custom Resources
629
-
630
- # Nested-stack tree (parent + children). Default child CFn names: '<parent>-<childLogicalId>'.
631
- cdkd export MyApp # leaf-first per-stack IMPORT loop
632
- cdkd export MyApp --cfn-child-stack-name 'MyApp~Database=my-app-db' # per-child name override
369
+ cdkd export MyApp # nested-stack tree: leaf-first per-stack IMPORT loop
633
370
  ```
634
371
 
635
- Accepts JSON and YAML templates. YAML round-trips through a CFn-aware codec
636
- (`src/cli/yaml-cfn.ts`) that preserves every shorthand intrinsic (`!Ref` /
637
- `!GetAtt` / `!Sub` / `!Join` / etc.), so a YAML-authored CFn stack stays YAML
638
- on the phase-1 IMPORT and phase-2 UPDATE changesets.
372
+ **Lambda-backed Custom Resources** (`Custom::*` /
373
+ `AWS::CloudFormation::CustomResource`) are NOT directly CFn-importable.
374
+ `--include-non-importable` opts into a 2-phase migration that re-CREATEs
375
+ them through CFn — the Custom Resource Lambda must be idempotent.
376
+ **Nested stacks** are supported via a leaf-first per-stack IMPORT loop
377
+ (AWS rejects `--include-nested-stacks` for IMPORT changesets).
378
+
379
+ See **[docs/import.md](docs/import.md)** for the full guide — Custom Resource
380
+ 2-phase flow, nested-stack adoption mechanics (`--cfn-child-stack-name`
381
+ per-child overrides, AWS's "Nest an existing stack" pattern), and the
382
+ design rationale at [docs/design/464-nested-stacks-export-import.md](docs/design/464-nested-stacks-export-import.md).
639
383
 
640
384
  ## Drift detection
641
385
 
@@ -675,24 +419,27 @@ Two `orphan` variants at different granularities:
675
419
  Both `cdkd destroy` (synth-driven) and `cdkd state destroy`
676
420
  (state-driven, no synth) delete AWS resources + state.
677
421
 
678
- ## `--remove-protection`: one-shot bypass for protected resources
422
+ ## VPC route DependsOn relaxation (on by default)
679
423
 
680
- CDK's `new Stack(app, 'X', { terminationProtection: true })` is honored
681
- by `cdkd destroy` (refused before any per-resource delete). The
682
- state-only path `cdkd state destroy` does NOT honor it that's the
683
- explicit "I know what I'm doing, ignore CDK guards" escape hatch.
424
+ CDK injects defensive `DependsOn` from VPC Lambdas onto private-subnet
425
+ routes. The dependency is real at runtime but NOT required at deploy
426
+ time. cdkd drops it by default so CloudFront + Lambda::Url propagation
427
+ runs in parallel with NAT stabilization (~50% faster on VPC+Lambda+CloudFront
428
+ stacks; bench-cdk-sample 398s → 181s). Pass
429
+ `cdkd deploy --no-aggressive-vpc-parallel` to opt out (e.g. when a
430
+ Custom Resource synchronously invokes a VPC Lambda outside cdkd's
431
+ Lambda-ServiceToken Active wait).
684
432
 
685
- For resource-level protection (`DeletionProtection` etc.), the standard
686
- workflow is edit CDK → redeploy → destroy. `--remove-protection` is the
687
- one-shot bypass:
433
+ See [docs/cli-reference.md](docs/cli-reference.md) for the full
434
+ type-pair allowlist and trade-off notes.
688
435
 
689
- `cdkd destroy --remove-protection` and `cdkd state destroy
690
- --remove-protection` flip every protection flag off in-place
691
- before each provider's delete API call so the destroy proceeds
692
- without an intermediate edit / redeploy. The flag covers both
693
- stack-level `terminationProtection` (the bypass logs a WARN line
694
- naming the stack) and resource-level protection on the following
695
- types:
436
+ ## `--remove-protection`: one-shot bypass for protected resources
437
+
438
+ `cdkd destroy --remove-protection` (and `cdkd state destroy --remove-protection`)
439
+ flips every protection flag off in-place before each provider's delete
440
+ API call, so a destroy proceeds without an intermediate edit / redeploy.
441
+ Covers stack-level `terminationProtection` (logged as a WARN) AND
442
+ resource-level protection on these types:
696
443
 
697
444
  | Resource type | Protection field |
698
445
  | --- | --- |
@@ -735,6 +482,18 @@ cdkd publish-assets -a cdk.out # skip synth, use pre-synthesized assembly
735
482
  See [docs/cli-reference.md](docs/cli-reference.md#publish-assets-synth--build--publish-no-deploy)
736
483
  for stack-selection rules and concurrency knobs.
737
484
 
485
+ ## Compatibility
486
+
487
+ cdkd supports the standard CloudFormation surface — intrinsic functions,
488
+ pseudo parameters, parameters / conditions, cross-stack / cross-region
489
+ references, asset publishing, custom resources, and so on. See
490
+ **[docs/supported-features.md](docs/supported-features.md)** for the
491
+ full reference. For per-resource-type provisioning support (SDK Providers
492
+ vs Cloud Control API fallback), see
493
+ **[docs/supported-resources.md](docs/supported-resources.md)**.
494
+
495
+ **Property-level coverage is incremental.** SDK Providers wire most but not every CFn property of a supported type. cdkd fails fast at pre-flight when a template uses a not-yet-implemented property, with the property name + a 1-click issue link. `--allow-unsupported-properties <Type>:<Prop>,...` is the safety valve when this is too strict (e.g. mid-life update on an existing resource); avoid it on security-meaningful properties (encryption / IAM / TLS). See [docs/cli-reference.md](docs/cli-reference.md#--allow-unsupported-properties-deploy).
496
+
738
497
  ## State Management
739
498
 
740
499
  State is stored in S3 with optimistic locking via S3 Conditional Writes