Importing existing resources
cdkd import adopts AWS resources that are already deployed (e.g. via
cdk deploy, manual creation, or another tool) into cdkd state, so the
next cdkd deploy updates them in-place instead of trying to CREATE
duplicates.
It reads the CDK app to find logical IDs, resource types, and dependencies, then matches each logical ID to a real AWS resource in one of three modes.
All examples below assume cdkd reads the CDK app command from cdk.json
(the typical case). Pass --app "<command>" only if you're running cdkd
outside the CDK project directory or want to override cdk.json.
Mode 1: auto (default — no flags)
cdkd import MyStack
Attempts to import every resource in the synthesized template, without naming physical ids by hand. Per resource, cdkd tries two lookups in order:
- By physical name — the template's own name property
(
ManagedPolicyName,TopicName,TableName, ...). - From CloudFormation — if a CloudFormation stack of the same name exists,
its
DescribeStackResourcesmapping. This is what makes adopting acdk deploy-managed stack work without naming ids by hand.
Note
There is deliberately no
aws:cdk:pathtag lookup.aws:cdk:pathis not a tag that exists on AWS resources: AWS rejects anyaws:-prefixed tag write (Tag keys beginning with aws: are reserved for system use), and CloudFormation keeps the value in the template's resourceMetadatawithout promoting it to a tag. cdkd once carried such a walk as a stage-3 fallback; because it could never match, it was removed from every provider. Stage 2 is what resolves a CFn-generated physical name — the usual CDK shape, which stage 1 alone cannot find.
Stage 2 is best-effort and never fatal: with no CloudFormation stack of that
name it is skipped silently, and if the call fails (missing
cloudformation:DescribeStackResources permission, throttling) cdkd warns and
falls back to stage 1. A resource that neither names itself nor lives in a
same-named CloudFormation stack comes back not found; adopt it with an
explicit --resource <logicalId>=<physicalId>.
To adopt a cdk deploy-managed stack and retire the CloudFormation stack
in one step, use
--migrate-from-cloudformation.
Plain auto mode adopts without touching the source stack. For a handful of
resources, name them explicitly with --resource (Mode 2).
Mode 2: selective (CDK CLI parity — when explicit overrides are given)
# Import ONLY MyBucket; the other resources in the template are left alone.
cdkd import MyStack --resource MyBucket=my-bucket-name
# Several resources at once (--resource is repeatable).
cdkd import MyStack \
--resource MyBucket=my-bucket-name \
--resource MyFn=my-function-name
# Composite physical ids: some types are identified by several segments
# joined with a `|` pipe. QUOTE the argument — an unquoted `|` is the shell
# pipe operator and would truncate the id.
cdkd import MyStack \
--resource 'MyGlueTable=my_database|my_table' \
--resource 'MyGetMethod=a1b2c3d4e5|xy9z8w|GET'
# CDK CLI compat: read overrides from a JSON file.
cdkd import MyStack --resource-mapping mapping.json
# mapping.json: { "MyBucket": "my-bucket-name", "MyFn": "my-function-name" }
# CDK CLI compat: inline JSON (handy for non-TTY CI scripts).
cdkd import MyStack --resource-mapping-inline '{"MyBucket":"my-bucket-name"}'
# Capture cdkd's resolved logicalId→physicalId mapping for re-use.
# Combine with --auto (or no flags) to record the auto-mode resolutions.
cdkd import MyStack --record-resource-mapping ./mapping.json
# mapping.json after the run: { "MyBucket": "my-bucket-name", ... }
# Replay non-interactively in CI:
cdkd import MyStack --resource-mapping ./mapping.json --yes
When at least one --resource flag (or a --resource-mapping /
--resource-mapping-inline payload) is supplied, only the listed
resources are imported. Every other resource in the template is
reported as out of scope and left out of state — the next cdkd deploy will treat them as new and CREATE them. This matches the
semantics of cdk import --resource-mapping /
--resource-mapping-inline. cdkd validates that every override key is
a real logical ID in the template; a typo aborts the run rather than
silently importing nothing. --resource-mapping and
--resource-mapping-inline are mutually exclusive — pick one source.
Use selective mode when you want to adopt a few specific resources out of a larger stack — for example, you have one S3 bucket that was created manually that you want cdkd to manage, while the rest of the stack will be deployed fresh.
Selective mode is non-destructive. When state already exists for
the stack, listed resources are merged into it: unlisted entries
already in state are preserved (no --force needed). --force is
only required when a listed override would overwrite a resource
already in state — that's the one case where the merge is destructive.
This is the right command for "I have a deployed stack and want to
adopt one more resource into it":
# Existing state has Queue + Topic; add Bucket without affecting them.
cdkd import MyStack --resource MyBucket=my-bucket-name
# Resulting state: Queue + Topic (preserved) + Bucket (newly imported).
Mode 3: hybrid (--auto with overrides)
cdkd import MyStack \
--resource MyBucket=my-bucket-name \
--auto
Listed resources use the explicit physical ID you supplied; every
other resource still goes through auto-resolution (Mode 1's physical-name
and CloudFormation DescribeStackResources lookups). Useful when one
resource cannot be auto-resolved (no explicit name, no CloudFormation
counterpart) but you want cdkd to find the rest automatically.
Common flags
| Flag | Purpose |
|---|---|
--dry-run |
Preview what would be imported. State is NOT written. |
--yes |
Skip the confirmation prompt before writing state (and the CloudFormation retirement prompt under --migrate-from-cloudformation). Required in CI: both prompts REFUSE a non-interactive stdin (NON_INTERACTIVE_CONFIRM, exit 1) rather than hanging on it — see cli-destroy.md. |
--force |
Confirm a destructive write to existing state — see below. |
--migrate-from-cloudformation [name] |
After cdkd state is written, retire the source CloudFormation stack: inject DeletionPolicy: Retain + UpdateReplacePolicy: Retain on every resource via UpdateStack, then DeleteStack. AWS resources are NOT deleted. See Migrating from cdk deploy (CloudFormation) to cdkd below. |
--use-cdk-bootstrap-assets |
Keep the CDK bootstrap asset destinations verbatim (skip the cdkd asset-storage rewrite) even when the region is opted in via cdkd bootstrap. Without it, import rewrites asset references (Lambda Code, image URIs, …) to the cdkd-owned storage — but records the pre-rewrite values in state, so the first post-import cdkd deploy repoints the live resources. See Importing a stack into a cdkd-assets region below and the asset-destinations section in docs/cli-bootstrap-gc.md. |
--force is only needed when the import would lose data:
- Auto / whole-stack mode + existing state: required. The resource map is rebuilt from the template, so any state entry not re-imported is dropped.
- Selective mode + listed override already in state: required. The listed entry is overwritten with the new physical id.
- Selective mode without a conflict (pure merge): not required. Unlisted state entries are preserved automatically.
- No existing state (first-time import): not required.
Migrating from cdk deploy (CloudFormation) to cdkd
If a stack was previously deployed via cdk deploy (and is therefore
managed by CloudFormation), cdkd import --migrate-from-cloudformation adopts
the resources into cdkd state AND retires the source CloudFormation
stack in one go:
cdkd import MyStack --migrate-from-cloudformation --yes
No --resource <id>=<physical> flags are needed — cdkd recovers each
resource's physical id directly from CloudFormation via
DescribeStackResources, so it works for both cdk deploy-managed and
cdkd deploy-managed stacks. (This same DescribeStackResources recovery
is what plain auto mode uses too — see Mode 1. aws:cdk:path
could never have helped here: upstream cdk deploy keeps the path in the
template's Metadata, and AWS reserves the aws: tag prefix so it is never
a real AWS tag on the resource.)
The flow:
DescribeStackResources— ask CloudFormation for every(LogicalResourceId, PhysicalResourceId)pair in the source stack. These are merged into the import overrides; user-supplied--resource <id>=<physical>flags take precedence over CFn's view.cdkd importruns and adopts every resource into cdkd state via each provider'simport()method, using the CFn-resolved physical ids as direct lookups.cdkdwrites state.DescribeStacks+GetTemplate+UpdateStackto injectDeletionPolicy: RetainandUpdateReplacePolicy: Retainon every resource — a metadata-only update.DeleteStack— every resource is nowRetain, so CloudFormation walks the stack and skips every resource. The stack record disappears; the underlying AWS resources are left intact and are now solely managed by cdkd.
Steps 1–5 all run inside the same lock so a concurrent cdkd deploy
cannot race the in-flight migration.
By default the CloudFormation stack name is taken from the cdkd stack name (the typical case — CDK uses the synthesized stack name as the CFn stack name). Pass an explicit value when the names differ:
cdkd import MyStack --migrate-from-cloudformation LegacyCfnStackName --yes
Nested stacks (recursive walk)
Source CloudFormation stacks that contain AWS::CloudFormation::Stack
children are walked recursively:
- Step 1 (
DescribeStackResources) becomes a recursive tree walk: for every nested-stack row, cdkd callsDescribeStackResources(<child ARN>)to enumerate the child's resources, and so on to arbitrary depth. Children at every level are fetched in parallel. - After the root state is written, cdkd writes one v6-keyed state
file per nested child at
cdkd/<parent>~<childLogicalId>/<region>/state.json, withparentStack/parentLogicalId/parentRegionpopulated per the v6 schema. Grandchildren getcdkd/<parent>~<child>~<grand>/<region>/state.json, recursively. Per-child locks are acquired before the write and released in reverse on success or failure. - The root parent's state entry for each nested-stack row carries the
synthesized cdkd-local ARN (
arn:cdkd-local:<region>:<account>:nested-stack/<parent>/<logicalId>) — NOT the real AWS child stack ARN. This matches whatNestedStackProvider.createwould write at deploy time, so an import-then-deploy cycle does not surface phantom property changes. - Step 4 (
UpdateStackwith Retain injection) is also recursive: for every nested-stack row in the parent template, cdkd fetches the child's template viaGetTemplate, recursively injects Retain on every non-nested-stack resource at every depth, uploads the modified child template to the cdkd state bucket, and rewrites the parent'sProperties.TemplateURLto point at it. AWS CFn's parent-sideDeleteStackcascades into each child — every leaf resource isRetain'd (so the AWS resource survives), and the child stack record gets deleted as a side effect.
Synth template ↔ AWS shape is validated up front: a nested-stack row
in the synth template that has no matching AWS child (or vice versa)
hard-errors before any state write, naming the offending logical id —
matching upstream cdk import's mismatch UX.
Limitations:
- JSON and YAML supported. The Retain-policy injection in step 4
parses the source CloudFormation template via cdkd's CFn-aware codec
(
src/cli/yaml-cfn.ts), which preserves every shorthand intrinsic (!Ref,!Sub,!GetAtt,!Join, ...) across the parse → inject-Retain → re-serialize round-trip. The phase-1 UPDATE submits the template in the same format as the source — a YAML-authored CFn stack stays YAML on the wire (with.yamlkey suffix andapplication/x-yamlcontent type when uploaded to the cdkd state bucket). - 1 MB template limit. Templates up to the inline 51,200-byte
TemplateBodyceiling are submitted directly. Larger templates are uploaded to the cdkd state bucket undercdkd-migrate-tmp/<stack>/<timestamp>.jsonand submitted viaTemplateURL; the transient object is deleted in afinallyimmediately afterUpdateStack, and its noncurrent versions are purged with it (the state bucket is versioned, so the delete alone would leave the template body readable byVersionId). That purge FAILS SOFT: it needss3:ListBucketVersionsands3:DeleteObjectVersionon the state bucket, and without them the migration still succeeds while a warning names the two grants and the previous versions survive — see state-management.md. Templates over the 1 MB CloudFormationTemplateURLceiling are structurally unsubmittable — cdkd fails with a clear error. cdkd state has already been written at that point, so re-runs and manual cleanup are both supported. The same ceiling applies independently to every uploaded nested-child template. - Not compatible with
--dry-run. The post-state-writeUpdateStack+DeleteStackare real side-effects and cannot be faithfully simulated. Use plaincdkd import --dry-runto preview per-resource import outcomes. - Partial imports leave unmanaged resources. If a resource cannot
be imported (no provider, AWS not-found, etc.),
DeleteStackskips it (Retain) and cdkd never wrote it into state — so the resource exists in AWS but unmanaged by both CloudFormation and cdkd. cdkd warns loudly when this happens; either re-import the missing resources first or accept the orphaning intentionally. - Bare
cdkd import(no migration flag) does NOT recurse. Without--migrate-from-cloudformation, eachAWS::CloudFormation::Stackrow is treated asunsupported(the underlyingNestedStackProviderhas noimport()method). Future work would add per-resource tag- based nested-stack adoption; for now, the migration flag is the only path.
After import
Run cdkd diff to see how the imported state lines up with the
template. If the resource's actual properties differ from the template,
the next cdkd deploy will UPDATE them to match. If you imported only
some resources (selective mode), the remaining template resources
appear as to create in the diff.
Importing a stack into a cdkd-assets region
When the target region is opted into cdkd-owned asset storage (cdkd bootstrap), the synthesized template's asset references (Lambda Code,
container image URIs, the IAM grants CDK generates on the asset bucket, …) are
rewritten from the CDK bootstrap locations (cdk-<qualifier>-assets-*) to the
cdkd-owned ones (cdkd-assets-*).
The AWS-side resources you are adopting still hold the CDK bootstrap
values, so cdkd records those pre-rewrite values in state — not the rewritten
ones. cdkd import prints an info line with the count when this applies.
What that means in practice:
- The first
cdkd diff/cdkd deployafter the import shows a change for every rewritten reference, and that deploy is what repoints the live resources at cdkd asset storage. - That deploy is required, not cosmetic. Without it, a resource whose live
value cdkd cannot read back (an
AWS::IAM::Policygranting read on the asset bucket — exactly whats3deploy.BucketDeploymentgenerates) would keep granting the CDK bootstrap bucket while the custom resource reads from the cdkd bucket, failing at runtime withAccessDenied. - Pass
--use-cdk-bootstrap-assets(or setcontext.cdkd.useCdkBootstrapAssetsincdk.json) to stay on the CDK bootstrap destinations entirely — no rewrite, no post-import change.
Provider coverage
This section lists every resource type whose cdkd provider implements
import(), grouped by how the import is resolved. Use it to decide
whether your stack can be adopted with a bare cdkd import MyStack
(all resources auto-resolve) or whether you need
--resource <id>=<physical> overrides for some of them.
For resource types without auto-lookup support (ApiGateway
sub-resources, niche services, anything in Cloud Control API), use the
explicit --resource <id>=<physicalId> override mode — selective mode
handles exactly this case. Resource types whose provider does not
implement import are reported as unsupported and skipped.
Important
A cdkd physical id is not always the id CloudFormation shows you. Types whose id shape is annotated below are identified by several segments joined with a
|pipe (<databaseName>|<tableName>,<restApiId>|<resourceId>|<httpMethod>, ...) — that composite is the value--resourceexpects and the valuecdkd state show/cdkd state resourcesprint. Quote it on a shell command line (--resource 'Id=db|table'); no escaping is needed inside a--resource-mappingJSON file. The full per-type format table lives in state-management.md.
Auto-resolved (no --resource flag needed)
These types implement import() and can resolve a physical id under auto
(default) and hybrid modes without an explicit --resource override,
when one of these applies:
- the template sets an explicit physical-name property (
BucketName,RoleName,TopicName, ...) — cdkd verifies / lists by that name; or - a CloudFormation stack of the same name exists — cdkd recovers every
physical id from its
DescribeStackResources, which is how acdk deploy-managed stack is adopted.
Note
There is no
aws:cdk:pathtag lookup. AWS reserves theaws:tag prefix, so that tag never exists on a real resource and a walk keyed on it could not match — CloudFormation keeps the construct path in the template'sMetadata, never as a tag. The former tag walk was removed from every provider. A CDK app that sets no explicit physical names and has no same-named CloudFormation stack must adopt those resources with--resource <logicalId>=<physicalId>.
Types with an import() that auto-resolves via the above:
- AWS::S3::Bucket
- AWS::Lambda::Function
- AWS::IAM::Role
- AWS::IAM::ManagedPolicy
- AWS::IAM::InstanceProfile
- AWS::IAM::User
- AWS::CertificateManager::Certificate
- AWS::IAM::Group
- AWS::SNS::Topic
- AWS::SQS::Queue
- AWS::DynamoDB::Table
- AWS::DynamoDB::GlobalTable
- AWS::Logs::LogGroup
- AWS::Events::EventBus
- AWS::Events::Rule
- AWS::KMS::Key
- AWS::KMS::Alias
- AWS::SecretsManager::Secret
- AWS::SSM::Parameter (the parameter NAME only — an ARN or a
name:version/name:labelselector is REFUSED with the name to pass instead, becauseGetParameteraccepts those forms whilePutParameter/DeleteParameterreject them, so adopting one would break the nextcdkd deployandcdkd destroy) - AWS::EC2::VPC
- AWS::EC2::Subnet
- AWS::EC2::SecurityGroup
- AWS::EC2::NatGateway
- AWS::EC2::EIP (accepts an
eipalloc-...allocation id, a public IP, or the composite<publicIp>|<allocationId>; cdkd normalizes and stores the composite) - AWS::RDS::DBInstance
- AWS::RDS::DBCluster
- AWS::RDS::DBProxy
- AWS::RDS::DBProxyEndpoint
- AWS::RDS::DBSubnetGroup
- AWS::DocDB::DBInstance
- AWS::DocDB::DBCluster
- AWS::DocDB::DBSubnetGroup
- AWS::Neptune::DBInstance
- AWS::Neptune::DBCluster
- AWS::Neptune::DBSubnetGroup
- AWS::ECS::Cluster
- AWS::ECS::Service (accepts the service ARN — the form cdkd stores — or the composite
<clusterArn>|<serviceName>) - AWS::ECS::TaskDefinition
- AWS::CloudFront::Distribution
- AWS::Cognito::UserPool
- AWS::ApiGatewayV2::Api
- AWS::AppSync::GraphQLApi
- AWS::CloudTrail::Trail
- AWS::CloudWatch::Alarm
- AWS::CodeBuild::Project
- AWS::CodeCommit::Repository
- AWS::ECR::Repository
- AWS::ElasticLoadBalancingV2::LoadBalancer
- AWS::ElasticLoadBalancingV2::TargetGroup
- AWS::Route53::HostedZone (resolved from the template's
NameviaListHostedZonesByName; when a public and a private zone share that name — split-horizon DNS — the template's ownVPCspicks the side, and a name that is still ambiguous is REFUSED rather than guessed at — reported as a failed row naming--resource <logicalId>=<hostedZoneId>, not as not-found. The adopted row records the sameId/NameServersattributes acdkd deployCREATE records, soFn::GetAtt <Zone>.NameServers— and theFn::Joinover it that CDK'szone.hostedZoneNameServersemits — resolves on an imported zone exactly as on a deployed one; a zone with no delegation set records the empty LIST. The delegation-set read is best-effort ONLY on the auto-resolved path, where it costs one extraGetHostedZone: if that call fails the zone is still adopted, with a warning, and any attributes already in state for it are preserved. With an explicit--resourceoverride there is no extra call — the id-verificationGetHostedZonesupplies the attributes — so a deniedGetHostedZonefails that row as it always has. Neither path heals on a plaincdkd deploy(an unchanged zone isNO_CHANGEand never callsupdate()); re-run the import for that row with--force, or make a template change that forces an UPDATE) - AWS::StepFunctions::StateMachine
- AWS::Glue::Database
- AWS::Glue::Table (stored and displayed as the composite
<databaseName>|<tableName>;--resourcealso accepts CloudFormation's bare table name, paired with the template'sDatabaseName) - AWS::Glue::Job
- AWS::Glue::Crawler
- AWS::Glue::Connection
- AWS::Glue::Trigger
- AWS::Glue::Workflow
- AWS::Glue::SecurityConfiguration
- AWS::Kinesis::Stream
- AWS::Kinesis::StreamConsumer
- AWS::KinesisFirehose::DeliveryStream
- AWS::WAFv2::WebACL
- AWS::EFS::FileSystem
- AWS::EFS::AccessPoint
- AWS::ElastiCache::CacheCluster
- AWS::ElastiCache::SubnetGroup
- AWS::Lambda::LayerVersion
- AWS::ServiceDiscovery::Service
- AWS::ServiceDiscovery::PrivateDnsNamespace
- AWS::ServiceDiscovery::HttpNamespace
- AWS::ServiceDiscovery::PublicDnsNamespace
- AWS::S3Express::DirectoryBucket
- AWS::S3Tables::TableBucket
- AWS::S3Vectors::VectorBucket
- AWS::DLM::LifecyclePolicy
- AWS::FSx::FileSystem
- AWS::Budgets::Budget (the template
Budget.BudgetNameresolves it without a flag) - AWS::EMR::Cluster (override with the cluster id
j-XXXX)
Override-only — no standalone identity / list API
These resource types have no AWS-side identity that cdkd can list and
match on. Use --resource <logicalId>=<physicalId> (or
--resource-mapping <file> / --resource-mapping-inline '<json>') to
provide the physical id explicitly.
- AWS::IAM::Policy (inline)
- AWS::IAM::UserToGroupAddition
- AWS::CloudWatch::AnomalyDetector (detectors are addressed by their metric descriptor, carry no tags, and have no name; pass any stable id via
--resource— cdkd re-derives the canonical descriptor-based id on the next replacement) - AWS::IAM::AccessKey (keys are not taggable and the template carries no property equal to the key id; pass the
AKIA...id via--resource, which cdkd verifies withGetAccessKeyLastUsed. Note: the imported record has no cachedSecretAccessKey— IAM returns it only fromCreateAccessKey— soFn::GetAtt [<key>, SecretAccessKey]cannot resolve for an imported key; mint a new key via replacement if the secret is needed) - AWS::Scheduler::Schedule (schedules are not taggable; the template
Name+GroupNamealso resolve without a flag) - AWS::CloudFormation::WaitConditionHandle (no AWS-queryable resource exists behind a handle; an explicit
--resourceid — or CloudFormation's pre-signed-URL physical id during--migrate-from-cloudformation— is recorded verbatim, and a synthesized placeholder is used otherwise) - AWS::CloudFront::OriginAccessControl (OACs are not taggable and the config's
Nameis a display field AWS does not accept as a lookup key; pass theE...id via--resource, which cdkd verifies withGetOriginAccessControl)
Override-only — sub-resources without a standalone identity
Sub-resources of a parent (an API Gateway Method belongs to a Resource
which belongs to a RestApi; a Route53 RecordSet belongs to a HostedZone)
have no standalone name or list API cdkd can resolve them by. Provide the
physical id via --resource.
- AWS::ApiGateway::Authorizer
- AWS::ApiGateway::Resource
- AWS::ApiGateway::Deployment
- AWS::ApiGateway::Stage
- AWS::ApiGateway::Method (composite:
--resource <logicalId>=<restApiId>|<resourceId>|<httpMethod>) - AWS::ApiGatewayV2::Stage
- AWS::ApiGatewayV2::Integration
- AWS::ApiGatewayV2::Route
- AWS::ApiGatewayV2::Authorizer
- AWS::AppSync::GraphQLSchema
- AWS::AppSync::DataSource (composite:
--resource <logicalId>=<apiId>|<name>) - AWS::AppSync::Resolver (composite:
--resource <logicalId>=<apiId>|<typeName>|<fieldName>) - AWS::AppSync::ApiKey (composite:
--resource <logicalId>=<apiId>|<apiKeyId>) - AWS::S3Tables::Namespace (composite:
--resource <logicalId>=<tableBucketARN>|<namespaceName>; only the parentAWS::S3Tables::TableBucketauto-resolves) - AWS::S3Tables::Table (composite:
--resource <logicalId>=<tableBucketARN>|<namespace>|<name>; only the parentAWS::S3Tables::TableBucketauto-resolves) - AWS::Route53::RecordSet (composite:
--resource <logicalId>=<hostedZoneId>|<name>|<type>, where<name>is the record name exactly as the template spells it — CDK emits a trailing dot) - AWS::ElasticLoadBalancingV2::Listener
- AWS::EFS::MountTarget
- AWS::RDS::DBProxyTargetGroup
- AWS::EC2::SecurityGroupIngress (pass the
sgr-...rule id — CloudFormation's own identifier for the type and the id the EC2 console shows. cdkd verifies it withDescribeSecurityGroupRules, declines an EGRESS rule id, and records its own composite<groupId>|<ipProtocol>|<fromPort>|<toPort>as the physical id plus the rule id as theIdattribute. The composite itself is deliberately NOT accepted here: the same tuple can name several rules)
Override-only — sub-resources / attachments
Attachment-style resources (a SNS Subscription pinning a Topic to an
endpoint, a Lambda Permission granting a principal access to a function)
have no taggable identity either. Provide the physical id via
--resource.
- AWS::SNS::Subscription
- AWS::SNS::TopicPolicy
- AWS::SQS::QueuePolicy
- AWS::S3::BucketPolicy
- AWS::Lambda::Permission (pass the bare statement id — the form cdkd stores; the legacy Cloud-Control-produced composite
<functionArn>|<statementId>is also read correctly) - AWS::Lambda::EventSourceMapping
- AWS::Lambda::Url
- AWS::Lambda::EventInvokeConfig (composite:
--resource <logicalId>=<functionName>|<qualifier>; a bare function name is read as qualifier$LATEST) - AWS::CloudFormation::CustomResource
- AWS::CloudFront::CloudFrontOriginAccessIdentity
- AWS::BedrockAgentCore::Runtime (adopt by ARN via
--resource) - AWS::BedrockAgentCore::Evaluator (accepts the evaluator ARN or bare id; an id is resolved to the canonical ARN via
GetEvaluator) - AWS::Lambda::MicrovmImage (adopt by image ARN via
--resource; a bare name is rejected —GetMicrovmImagerequires the ARN)
Note: AWS::BedrockAgentCore::Browser / AWS::BedrockAgentCore::CodeInterpreter
are adopt-only singletons pointing at the AWS-managed defaults; their import is
a live auto-lookup (GetBrowser / GetCodeInterpreter) that needs no
--resource override at all.
Cloud Control API fallback
Any other CC-API-supported resource type can be imported via the same
--resource <logicalId>=<physicalId> override. cdkd does not run
auto-lookup over Cloud Control API by default — it would issue an
aws-cloudcontrol:ListResources call per type, which is too expensive
for whole-stack adoption.
Unsupported
Resource types whose cdkd provider does not implement import() (or
which have no provider at all) are reported as unsupported in the
import summary and skipped. CDK Stages — separate top-level stacks
under one app — are fine; pass the stack's display path or physical
name as the positional argument.
Nested CloudFormation stacks (AWS::CloudFormation::Stack): bare
cdkd import (auto / selective / hybrid mode) still treats each nested-
stack row as unsupported — there is no per-resource import() on the
NestedStackProvider. To adopt a parent stack with nested children,
use cdkd import --migrate-from-cloudformation instead, which recursively
walks the tree, writes one v6-keyed state file per child
(cdkd/<parent>~<childLogicalId>/<region>/state.json), and retires the
whole tree via a single parent-side DeleteStack cascade. See the
--migrate-from-cloudformation section below for details.
AWS::AutoScaling::AutoScalingGroup is also currently unsupported —
the SDK provider exists for create / update / delete / readCurrentState
but has not yet been wired for import(). Track-able via a follow-up
that adds an override-only import() keyed on the group name.
AWS::EMR::InstanceGroupConfig / AWS::EMR::InstanceFleetConfig are
likewise currently unsupported for import — the SDK providers exist for
create / update / delete but not import(). They are cluster
sub-resources with no standalone name (they are listed
via ListInstanceGroups / ListInstanceFleets under a parent
ClusterId), so a future override-only import() keyed on the group /
fleet id (ig-XXXX / if-XXXX) is the natural follow-up.
Adding a new entry
When adding import() support to a provider, add the resource type to
the appropriate section above. Keep entries one-per-line so parallel
PRs don't conflict on rebase.
cdkd import vs upstream cdk import
cdkd's import command mirrors the surface of upstream
cdk import
where it can, but the underlying mechanism is fundamentally different
and a handful of upstream-only flags are not implemented. Use this
table to predict behavior when migrating from cdk import.
| Topic | cdk import (upstream) |
cdkd import |
|---|---|---|
| Mechanism | CloudFormation CreateChangeSet with ResourcesToImport — atomic, all-or-nothing. |
Per-resource SDK calls (e.g. s3:HeadBucket, lambda:GetFunction, IAM ListRoleTags). Not atomic. |
| Failure mode | Failed import rolls the changeset back; the stack is left unchanged. | Per-resource: imported / skipped-not-found / skipped-no-impl / skipped-out-of-scope / failed rows are summarized. State is written for whatever succeeded — but only after a confirmation prompt (or --yes), so a partial run is opt-in. To roll a partial import back, use cdkd state orphan <stack> (drops the state record only). |
Selective mode (--resource-mapping <file>) |
Supported. Listed resources are imported; unlisted resources cause the changeset to fail. | Supported. Listed resources are imported; unlisted resources are reported as out of scope and left out of state (next cdkd deploy will CREATE them). |
Selective mode (--resource <id>=<physical> repeatable) |
Not supported (upstream uses interactive prompts or a mapping file). | Supported as cdkd's CLI-friendly equivalent. |
--resource-mapping-inline '<json>' |
Supported (use in non-TTY environments). | Supported. Same shape as --resource-mapping <file> but supplied as a string — useful for non-TTY CI scripts that do not want a separate file. Mutually exclusive with --resource-mapping. |
--record-resource-mapping <file> |
Supported (writes the mapping the user typed at the prompt to a file for re-use). | Supported. Writes the resolved {logicalId: physicalId} map (covers explicit overrides AND auto-mode name / CloudFormation resolution) to the file before the confirmation prompt. The file is produced even if the user says "no" or under --dry-run, so the resolved data is never thrown away. |
| Interactive prompt for missing IDs | Default in TTY — prompts for every resource not covered by a mapping file. | Not supported. cdkd is non-interactive: missing logical IDs are resolved from the template's physical-name property, then from a same-named CloudFormation stack's DescribeStackResources, in auto / hybrid modes, or skipped as out of scope in selective mode. The only prompt is the final "write state?" confirmation, which --yes skips. |
| Typo'd logical ID | Aborts with a clear error before any AWS calls. | Aborts with a clear error before any AWS calls — checked against the synthesized template. |
| Whole-stack import with no per-resource ids | Not supported. | cdkd-specific. With no flags cdkd resolves each resource from the template's physical-name property, then from a same-named CloudFormation stack's DescribeStackResources. Use --migrate-from-cloudformation when you also want the source CloudFormation stack retired. |
| Hybrid mode (overrides + auto-resolution) | Not supported. | cdkd-specific. --auto together with --resource lets listed resources use the explicit physical id while everything else still goes through auto-resolution (name property + CloudFormation lookup). |
Nested stacks (AWS::CloudFormation::Stack) |
Explicitly unsupported. | Supported via cdkd import --migrate-from-cloudformation: recursively walks the tree via DescribeStackResources, writes one v6-keyed state file per child (cdkd/<parent>~<childLogicalId>/<region>/state.json), recursively injects DeletionPolicy: Retain into every leaf resource template, then retires the whole tree via a single parent-side DeleteStack cascade. Bare cdkd import (auto / selective / hybrid mode) still reports each nested-stack row as unsupported. CDK Stages (separate top-level stacks) are also fine: pass the stack's display path or physical name as the positional argument. |
| Bootstrap requirement | Bootstrap v12+ (deploy role needs to read the encrypted staging bucket). | cdkd's own state bucket; no CDK bootstrap version requirement. |
| Resource-type coverage | Whatever CloudFormation supports for import. | The set of cdkd providers that implement import() — see Provider coverage above. For any other CC-API-supported type, use --resource <id>=<physical> to drive the Cloud Control API fallback. The two lists overlap heavily but are not identical. |
| Confirmation prompt before writing state | n/a (CloudFormation operates atomically). | Yes — cdkd asks before writing the state file. Skip with --yes. |
--force |
"Continue even if the diff includes updates or deletions" — about diff strictness. | "Confirm a destructive write to existing state" — required for auto/whole-stack rebuild and for overwriting a listed entry already in state; not required for a pure selective merge. Same flag name, different meaning. |
--dry-run |
Implied by --no-execute (creates the changeset without executing). |
Native: shows the import plan and exits without writing state. |
Practical implications when migrating from cdk import
- If you script around
--resource-mapping <file>: behavior matches. The file format ({"LogicalId": "physical-id"}) is the same. - If you script around
--resource-mapping-inline: behavior matches. The JSON shape is the same as--resource-mapping <file>. - If you script around
--record-resource-mapping <file>: behavior matches. cdkd writes the resolved{logicalId: physicalId}map to the file before the confirmation prompt — and even if the user says "no" or under--dry-run— so you can capture cdkd's auto-mode resolution result and replay it via--resource-mappingin CI. - If your workflow relies on the interactive prompt: rewrite as
--resource-mapping <file>. cdkd will not prompt. - If you rely on atomic rollback: cdkd cannot offer that — its
per-resource model writes state only after the full pass completes
(and after confirmation), so a partial run is bounded, but if a
later resource fails after several earlier ones already returned
successfully and you confirm the write, those earlier ones are
in cdkd state. Use
cdkd state orphan <stack>to back out. - If you import nested stacks: neither tool supports this. Convert to top-level CDK stacks first.