Import Stack Outputs in AWS CDK for Cross Stack References

avatar

Borislav Hadzhiev

Sat Apr 24 20214 min read

banner

Photo by Andrew Ly

Updated on Sat Apr 24 2021

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/aws-lambda'; import {NodejsFunction} from '@aws-cdk/aws-lambda-nodejs'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; 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, }, });

I'll now execute a deployment:

shell
npx 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/aws-lambda'; import {NodejsFunction} from '@aws-cdk/aws-lambda-nodejs'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; 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_14_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:

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};

In the code snippet we've used the importValue static method on the Fn class. 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 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 in our CDK code, at synthesis time.

If we take a look at the lambda console, we can see that after we executed the deployment, 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 other stack
  • We can't delete a stack if its outputs are referenced by another 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 an 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

Further Reading #

Add me on LinkedIn

I'm a Web Developer with TypeScript, React.js, Node.js and AWS experience.

Let's connect on LinkedIn

Join my newsletter

I'll send you 1 email a week with links to all of the articles I've written that week

Buy Me A Coffee