Last updated: Jan 26, 2024
Reading timeยท4 min
To reference a resource value from a different stack we use the Import Value static method on the Fn class.
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.
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, }, });
I'll now run the deploy
command.
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
.
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.
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.
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:
npx aws-cdk deploy my-cdk-stack
The call to console.log
with the imported value prints a 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.
At this point, we were successfully able to use the importValue
method to
import a value that was exported from a different stack.
Some of the restrictions when working with import value and cross-stack references are:
exportNames
we use have to be unique within a region.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.
myBucket
cannot be deleted as it is in use by my-cdk-stackIf 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:
If we try to delete a stack that exports outputs that are imported by other stacks, we would also get an error:
myBucket
cannot be deleted as it is in use by my-cdk-stack)You can learn more about the related topics by checking out the following tutorials: