Import Stack Outputs in AWS CDK for Cross-Stack References

avatar
Borislav Hadzhiev

Last updated: Jan 26, 2024
4 min

banner

# Using Import Value for Cross-Stack References in CDK

To reference a resource value from a different stack we use the Import Value static method on the Fn class.

The code for this article is available on GitHub

First, we have to use an Output to export the value we'll eventually import. In this example, I'll create an S3 Bucket and export its name as an Output.

lib/cdk-starter-stack.ts
import * as lambda from 'aws-cdk-lib/aws-lambda'; import {NodejsFunction} from 'aws-cdk-lib/aws-lambda-nodejs'; import * as s3 from 'aws-cdk-lib/aws-s3'; import * as cdk from 'aws-cdk-lib'; import * as path from 'path'; export class S3BucketStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props: cdk.StackProps) { super(scope, id, props); const myBucket = new s3.Bucket(this, 'myBucket', { removalPolicy: cdk.RemovalPolicy.DESTROY, }); // ๐Ÿ‘‡ export myBucket for cross-stack reference new cdk.CfnOutput(this, 'myBucketRef', { value: myBucket.bucketName, description: 'The name of the s3 bucket', exportName: 'myBucket', }); } } const app = new cdk.App(); new S3BucketStack(app, 'my-s3-stack', { stackName: 'my-s3-stack', env: { region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT, }, });
If you still use CDK version 1, switch to the cdk-v1 branch in the GitHub repository.

I'll now run the deploy command.

shell
npx aws-cdk deploy my-s3-stack

If we take a look at the CloudFormation console and click on the Outputs section of the stack, we can see that the exportName of the value we are going to import is myBucket.

outputs stack

Next, let's use Import Value to import the bucket name into another stack and pass it as an environment variable to a Lambda function.

lib/cdk-starter-stack.ts
import * as lambda from 'aws-cdk-lib/aws-lambda'; import {NodejsFunction} from 'aws-cdk-lib/aws-lambda-nodejs'; import * as s3 from 'aws-cdk-lib/aws-s3'; import * as cdk from 'aws-cdk-lib'; import * as path from 'path'; export class MyCdkStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props: cdk.StackProps) { super(scope, id, props); const importedBucketValue = cdk.Fn.importValue('myBucket'); console.log('importedBucketValue ๐Ÿ‘‰', importedBucketValue.toString()); const myFunction = new NodejsFunction(this, 'my-function', { // ๐Ÿ‘‡ Pass the imported bucket name as env var environment: { BUCKET_NAME: importedBucketValue.toString(), }, runtime: lambda.Runtime.NODEJS_18_X, timeout: cdk.Duration.seconds(4), handler: 'main', entry: path.join(__dirname, `/../src/my-lambda/index.js`), }); } } const app = new cdk.App(); new MyCdkStack(app, 'my-cdk-stack', { stackName: 'my-cdk-stack', env: { region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT, }, });

The code of the Lambda function could be as simple as follows.

src/my-lambda/index.js
async function main(event) { console.log('BUCKET_NAME ๐Ÿ‘‰', process.env.BUCKET_NAME); return {body: JSON.stringify({message: 'SUCCESS'}), statusCode: 200}; } module.exports = {main};

We used the importValue static method on the Fnclass. The only argument the method takes is the exportName of the value we want to import.

I'll then issue the deploy command:

shell
npx aws-cdk deploy my-cdk-stack

The call to console.log with the imported value prints a token:

deploy import token

Tokens in CDK are encoded values that get resolved at deployment time by CloudFormation. This means that we don't have access to the resolved value at synthesis time in our CDK code.

If we take a look at the lambda console, we can see that after we ran the deploy command, the imported value has been resolved.

lambda environment variables

At this point, we were successfully able to use the importValue method to import a value that was exported from a different stack.

# Caveats when working with Import Value and Cross-Stack References

Some of the restrictions when working with import value and cross-stack references are:

  • We can only import values that are exported from stacks in the same region.
  • The exportNames we use have to be unique within a region.
  • We can't update or remove outputs that are imported by another stack.
  • We can't delete a stack if its outputs are referenced by other stacks.

# Trying to Delete an Export that is Imported by other Stacks

For example, I'll try to delete the Output in the my-s3-bucket stack.

export class S3BucketStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props: cdk.StackProps) { super(scope, id, props); const myBucket = new s3.Bucket(this, 'myBucket', { removalPolicy: cdk.RemovalPolicy.DESTROY, }); // ๐Ÿ‘‡ has been removed // new cdk.CfnOutput(this, 'myBucketRef', { // value: myBucket.bucketName, // description: 'The name of the s3 bucket', // exportName: 'myBucket', // }); } }

If I now run the cdk deploy command, I'd get the following error.

Export myBucket cannot be deleted as it is in use by my-cdk-stack

delete export error

# Trying to Provision Multiple Exports with the same Name

If we try to provision multiple Outputs with the same Export name, we would also get an error.

export class S3BucketStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props: cdk.StackProps) { super(scope, id, props); const myBucket = new s3.Bucket(this, 'myBucket', { removalPolicy: cdk.RemovalPolicy.DESTROY, }); new cdk.CfnOutput(this, 'myBucketRef', { value: myBucket.bucketName, description: 'The name of the s3 bucket', // ๐Ÿ‘‡ same name exportName: 'myBucket', }); new cdk.CfnOutput(this, 'myBucketRef2', { value: myBucket.bucketName, description: 'The name of the s3 bucket', // ๐Ÿ‘‡ same name exportName: 'myBucket', }); } }

If I now run the cdk deploy command it outputs the error message:

The Outputs section contains duplicate Export names: [myBucket]. Specify a unique name for each export.

duplicate export names

# Trying to Delete a Stack that Exports Values imported by Another Stack

If we try to delete a stack that exports outputs that are imported by other stacks, we would also get an error:

Error: Failed to destroy my-s3-stack: (Export myBucket cannot be deleted as it is in use by my-cdk-stack)

delete exporter stack

# Additional Resources

You can learn more about the related topics by checking out the following tutorials:

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.

Copyright ยฉ 2024 Borislav Hadzhiev