Skip to content
cdkd

cdkd export

cdkd export hands a stack that cdkd manages over to CloudFormation. It is the opposite direction of cdkd import.

The AWS resources are not modified. CloudFormation adopts them into a new CloudFormation stack, and cdkd then deletes its own state record for the stack. From then on you change the stack with cdk deploy or aws cloudformation.

What cdkd export does to the ownership of a stackBefore the export, cdkd owns the stack: a state record in S3 tracks its resources and cdkd deploy changes them. cdkd export builds a CloudFormation IMPORT changeset from that record and the synthesized template, without modifying the AWS resources. After the export, CloudFormation owns the stack: a CloudFormation stack holds the same resources, the cdkd state record is deleted, and cdk deploy changes them.Before: cdkd owns the stackA state record in S3 tracks the resourcesYou change them with cdkd deploycdkd exportIMPORT changeset built from the staterecord and the synthesized templateThe AWS resources are not modifiedAfter: CloudFormation owns the stackA CloudFormation stackholds the same resourcesThe cdkd state record is deletedYou change them with cdk deployWhat cdkd export does to the ownership of a stackBefore the export, cdkd owns the stack: a state record in S3 tracks its resources and cdkd deploy changes them. cdkd export builds a CloudFormation IMPORT changeset from that record and the synthesized template, without modifying the AWS resources. After the export, CloudFormation owns the stack: a CloudFormation stack holds the same resources, the cdkd state record is deleted, and cdk deploy changes them.Before: cdkd owns the stackA state record in S3 tracks the resourcesYou change them with cdkd deploycdkd exportIMPORT changeset built from the staterecord and the synthesized templateThe AWS resources are not modifiedAfter: CloudFormation owns the stackA CloudFormation stack holds the same resourcesThe cdkd state record is deletedYou change them with cdk deploy
# print the import plan, change nothing
cdkd export MyStack --dry-run

# export; the CloudFormation stack is named MyStack
cdkd export MyStack

# name the CloudFormation stack yourself
cdkd export MyStack --cfn-stack-name MyStack-CFn

# also migrate Custom Resources (two phases)
cdkd export MyStack --include-non-importable

# use this template instead of synthesizing
cdkd export MyStack --template template.yaml

# single-stack app: the stack is detected
cdkd export

Hand a Stack to CloudFormation is the short guide to deciding whether a stack is ready. This page is the reference.

Export a stack

This example exports a stack with one S3 bucket and one DynamoDB table. The output is abridged to the lines you act on.

  1. Preview the plan

    cdkd export MyStack --dry-run
    
    Migrating cdkd stack 'MyStack' ('us-east-1') → CloudFormation stack 'MyStack'
    
    Import plan for CloudFormation stack 'MyStack':
      UploadsBucket5E5E9B33 (AWS::S3::Bucket) ← BucketName=mystack-uploadsbucket5e5e9b33-k2j4h8x1
      JobsTable1A2B3C4D (AWS::DynamoDB::Table) ← TableName=MyStack-JobsTable1A2B3C4D-9QK2M
    
    --dry-run: no CloudFormation changeset will be created.
    

    The plan lists each resource with the identifier CloudFormation will adopt it by. It also reports anything that blocks the export. --dry-run takes no lock, creates no changeset and writes nothing.

  2. Run the export

    cdkd export MyStack
    
    ✓ Phase 1: CloudFormation stack 'MyStack' created via IMPORT. 2 resource(s) imported.
    cdkd state for 'MyStack' ('us-east-1') removed. Manage the stack with 'cdk deploy' or 'aws cloudformation' from here on.
    
    Next steps — manage the stack with CDK CLI from now on:
      cdk diff MyStack    # verify synth matches what CFn now holds
      cdk deploy MyStack  # subsequent updates
    

    cdkd prints the same plan, asks for confirmation, imports the resources and deletes its state record.

  3. Check the result with the CDK CLI

    cdk diff MyStack
    

    The diff is empty for resources whose names AWS generated, and for sub-resources that reference their parent. One case is not empty; see Stacks with prefixed physical names.

What blocks an export

cdkd builds the whole plan before it locks the stack or submits anything to CloudFormation. When a stack cannot be exported, one message names every offending resource, and nothing has changed. You can fix them all and run the command again.

These are the blocks you are likely to meet:

The stack has What to do
A destination stack name that already exists in CloudFormation Pick another name with --cfn-stack-name, or delete that stack.
A Custom Resource Pass --include-non-importable.
A resource type CloudFormation cannot import Remove or destroy the resource first.
Context passed with -c Move it into cdk.json.
A template Parameter with no value Pass --parameter Key=Value.

A Custom Resource is a resource of type Custom::* or AWS::CloudFormation::CustomResource.

A stack whose last deploy failed or was interrupted is not blocked. cdkd asks before it exports such a stack; see Confirmation prompts.

cdkd export: what blocks an export has the rarer blocks, including a damaged state record and a recorded value of ***.

In this section

Options

Flag Default Description
[stack] — Stack to export. Detected when the app defines a single stack.
--dry-run off Print the import plan and exit. No lock, no changeset, no AWS writes.
--cfn-stack-name <name> the cdkd stack name Name of the destination CloudFormation stack.
--cfn-child-stack-name <pair...> ~ replaced by - Name for a nested child, as '<cdkdName>=<cfnName>'. Repeatable.
--template <path> — Use this CloudFormation template (JSON or YAML) and skip synthesis.
--stack-region <region> — Region of the cdkd state record. Required when the stack name has state in several regions.
--include-non-importable off Migrate Custom Resources in a second phase instead of refusing.
--no-recreate-import-unsupported off Refuse on AWS::IAM::Policy instead of deleting and re-creating it.
--parameter <key=value...> template Default Template Parameter value. Repeatable.
--accept-transient-context off Allow -c overrides at export time.
--strict-cross-stack off Refuse when other stacks in the app read this one through Fn::GetStackOutput.
--skip-import-support-preflight off Skip the checks for types CloudFormation cannot import.
-y, --yes off Answer the confirmation prompts automatically.
-a, --app <command> cdk.json / CDKD_APP CDK app command, or a synthesized cloud assembly directory.
--output <path> cdk.out Synthesis output directory.
-c, --context <key=value...> — Context values. Refused without --accept-transient-context.
--state-bucket <bucket> CDKD_STATE_BUCKET / cdk.json S3 bucket holding the state records.
--state-prefix <prefix> cdkd S3 key prefix for state files.
--profile <profile> — AWS profile.
--role-arn <arn> CDKD_ROLE_ARN IAM role to assume for AWS API calls.
--verbose off Verbose logging.

How the export runs

An export is a plan, a lock, one or two CloudFormation changesets, and a cleanup. A changeset is the unit in which CloudFormation applies a change to a stack. An IMPORT changeset adopts existing resources into a stack without modifying them.

The steps of a cdkd export runcdkd export first builds the import plan: it synthesizes the app or reads --template, classifies every resource and resolves each identifier, with no lock and no AWS writes, and reports blocked resources here. It then locks the stack and asks for confirmation; --dry-run stops before this step. Phase 1 creates the CloudFormation stack with an IMPORT changeset. Phase 2, which runs only when the stack has Custom Resources or AWS::IAM::Policy resources, deletes those inline policies and submits an UPDATE changeset with the full template; a failure there leaves both the CloudFormation stack and the cdkd state in place. Last, cdkd deletes its state record and releases the lock.Build the import planSynthesize the app or read --templateClassify resources, resolve identifiersNo lock and no AWS writes. Blockedresources are reported here.Lock the stack, ask for confirmation--dry-run stops before this stepPhase 1: IMPORT changesetCreates the CloudFormation stackfrom the importable resourcesPhase 2: UPDATE changesetOnly with Custom Resourcesor AWS::IAM::PolicyDeletes the inline policies, thenCloudFormation creates both kindsA failure here leaves the CloudFormationstack and the cdkd state in placeDelete the cdkd staterecord, release the lockThe steps of a cdkd export runcdkd export first builds the import plan: it synthesizes the app or reads --template, classifies every resource and resolves each identifier, with no lock and no AWS writes, and reports blocked resources here. It then locks the stack and asks for confirmation; --dry-run stops before this step. Phase 1 creates the CloudFormation stack with an IMPORT changeset. Phase 2, which runs only when the stack has Custom Resources or AWS::IAM::Policy resources, deletes those inline policies and submits an UPDATE changeset with the full template; a failure there leaves both the CloudFormation stack and the cdkd state in place. Last, cdkd deletes its state record and releases the lock.Build the import planSynthesize the app or read --templateClassify resources, resolve identifiersNo lock and no AWS writes. Blockedresources are reported here.Lock the stack, ask for confirmation--dry-run stops before this stepPhase 1: IMPORT changesetCreates the CloudFormation stackfrom the importable resourcesPhase 2: UPDATE changesetOnly with Custom Resources or AWS::IAM::PolicyDeletes the inline policies, thenCloudFormation creates both kindsA failure here leaves the CloudFormationstack and the cdkd state in placeDelete the cdkd staterecord, release the lock

The lock keeps a concurrent cdkd deploy or cdkd destroy out of the stack for the whole run.

Most stacks need only phase 1. Phase 2 runs when the stack has Custom Resources or AWS::IAM::Policy resources, which CloudFormation cannot import and has to create instead. cdkd export: custom resources and IAM policies describes it.

cdkd deletes its state record only after the last changeset completes. A failure before that point leaves the record intact.

When a changeset fails

cdkd fetches the CloudFormation stack events and prints the failure reason for each resource. The cdkd state record is kept.

Two failures print recovery steps of their own: a failed phase 2, and a failure inside a nested-stack tree.

Values printed as (not shown: it is not a plain identifier)

Plans and error messages contain commands for you to paste. A stack name, physical id or context value that is not a plain identifier is not safe to paste, so cdkd prints (not shown: it is not a plain identifier) in its place. cdkd state show prints the stored value.

Confirmation prompts

cdkd export asks before it changes anything. -y / --yes answers every prompt, and --dry-run never prompts.

Prompt Raised when
Export anyway? A previous deploy of the stack failed or was interrupted and has not been rolled back.
Migration confirmation Before the changeset for a single stack is submitted.
Tree-wide confirmation Before the per-stack loop for a nested-stack tree starts.

Export anyway? deserves a pause. Exporting a half-deployed stack is rarely what you want. Run cdkd rollback MyStack to revert the deploy, or cdkd deploy to finish it, and then export.

The prompts need a terminal. When stdin is not a terminal, each prompt refuses with exit code 1 instead of waiting, and cdkd releases the stack lock if it holds it. Pass --yes in CI.

How cdkd identifies each resource

To adopt a resource, CloudFormation needs the identifier it knows that resource by: a bucket's BucketName, a table's TableName. For most types that identifier is the physical id cdkd already recorded, and you have nothing to do.

cdkd reads the identifier's property names from the type's CloudFormation registry schema, through cloudformation:DescribeType. A built-in table for about thirty common single-field types is the fallback.

Composite identifiers

Some types have an identifier with more than one field. cdkd builds it from the physical id. Where a field is the parent's id (ApiId, FunctionName, RestApiId), cdkd takes it from the recorded properties.

Service Resource types
API Gateway (REST) AWS::ApiGateway::Method, AWS::ApiGateway::Resource, AWS::ApiGateway::Deployment, AWS::ApiGateway::Stage, AWS::ApiGateway::Authorizer, AWS::ApiGateway::Model, AWS::ApiGateway::RequestValidator
API Gateway (HTTP) AWS::ApiGatewayV2::Integration, AWS::ApiGatewayV2::Route, AWS::ApiGatewayV2::Stage
EC2 AWS::EC2::VPCGatewayAttachment, AWS::EC2::VPCCidrBlock, AWS::EC2::Route, AWS::EC2::EIP
Lambda AWS::Lambda::EventInvokeConfig, AWS::Lambda::Permission
AppSync AWS::AppSync::ApiKey
S3 Tables AWS::S3Tables::Namespace

A type with a multi-field identifier that is not in this table is refused, and the message names the type.

Five more types use an identifier that cdkd reads from what it recorded at deploy time. See Identifiers read from recorded attributes.

Cross-stack consumers

Other stacks in the same CDK app may read this stack's outputs through Fn::GetStackOutput. Those consumers keep working after the export.

The reason is a fallback in the consumer's deploy. After the export the outputs live in CloudFormation. A consumer that does not find them in cdkd state reads them from the CloudFormation stack instead. cdkd export checks for such consumers and warns that their references now depend on that fallback. Pass --strict-cross-stack to refuse instead.

Edge cases

  • A consumer deployed with --no-cfn-fallback. That consumer breaks, because it does not read from CloudFormation. Plan a multi-stack migration from the leaves up in that case.
  • Consumers outside the CDK app. cdkd cannot see them. Check those yourself.

Use Another Stack's Outputs describes the fallback.

Exit codes

Code Meaning
0 The stack was handed over and cdkd state was deleted. A declined prompt and --dry-run also exit 0.
1 Any failure: a blocked resource, a rejected changeset, an AWS authentication error, a held lock, or a prompt on a non-interactive stdin.

Last updated: