Last updated: Jan 27, 2024
Reading timeยท7 min

To access the accountId, region and availabilityZones properties in our
CDK code, we have to set the env property when instantiating our Stack.
import * as cdk from 'aws-cdk-lib'; export class MyCdkStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); console.log('accountId: ', cdk.Stack.of(this).account); console.log('region: ', cdk.Stack.of(this).region); console.log('availability zones: ', cdk.Stack.of(this).availabilityZones); } } const app = new cdk.App(); new MyCdkStack(app, `my-cdk-stack-dev`, { stackName: `my-cdk-stack-dev`, // ๐ now explicitly setting account and region env: { region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT, }, });
If we run the npx aws-cdk synth command, we can see that we are now able to
access the accountId, region and availabilityZones at synthesis time in
our CDK code.

I have excluded the accountId property from the screenshot, but it too was resolved.
The
recommended way by the CDK team
to get access to the accountId and region properties is to use the
Stack.of(this).account and Stack.of(this).region API.
Notice that in our code snippet above, we used two environment variables that are available in our CDK environment.
{ region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT, }
The value of these environment variables depends on whether we pass in a
--profile flag when we issue the npx aws-cdk deploy command.
For example, if we specify a profile, the values of CDK_DEFAULT_REGION and
CDK_DEFAULT_ACCOUNT would correspond to the profile's region and account
properties.
npx aws-cdk deploy --profile myprofile my-stack
If we don't set the --profile flag, the values will correspond to the default
profile's region and account properties.
npx aws-cdk deploy my-stack
Either way, if we have the AWS CLI configured on our machine, by passing in the
CDK_DEFAULT_REGION and CDK_DEFAULT_ACCOUNT properties we are explicitly
setting the environment, which enables us to access the properties at synthesis
time in our CDK code.
CDK_DEFAULT_REGION and CDK_DEFAULT_ACCOUNT environment variables. The default profile of the different developers working on the project could be set to different regions and accounts.Instead, just pass the values as environment variables explicitly. You can hard code the values, manage them as secrets, etc.
An environment-agnostic stack is a stack where we haven't explicitly set the
account and region properties.
const app = new cdk.App(); new MyCdkStack(app, `my-cdk-stack-dev`, { stackName: `my-cdk-stack-dev`, // ๐ we are not explicitly setting the region and account // env: { // region: 'us-east-1', // account: 123456789, // } });
Because we haven't explicitly set the env property in our stack, the account
and region properties will be resolved by CloudFormation at deployment time
rather than synthesis time.
Since we want access to these properties in our CDK code we have to find a way to resolve them at synthesis time.
Let's try to get the accountId, region and availabilityZones properties in
an environment agnostic stack, without explicitly setting the env property.
import * as cdk from 'aws-cdk-lib'; export class MyCdkStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); // ๐ recommended way to get access to the properties console.log('accountId: ', cdk.Stack.of(this).account); console.log('region: ', cdk.Stack.of(this).region); console.log('availability zones: ', cdk.Stack.of(this).availabilityZones); } } const app = new cdk.App(); new MyCdkStack(app, `my-cdk-stack-dev`, { stackName: `my-cdk-stack-dev`, // ๐ we are not explicitly setting the region and account // env: { // region: 'us-east-1', // account: 123456789, // } tags: {env: 'dev'}, });
We only get unresolved token values that will eventually be resolved at deployment time by CloudFormation.

The solution is to explicitly set the account and region and call the
Stack.of APIs:
console.log('accountId:', cdk.Stack.of(this).account); console.log('region', cdk.Stack.of(this).region); console.log('availability zones', cdk.Stack.of(this).availabilityZones);
Every AWS Region consists of multiple Availability Zones. Usually when we provision resources we have to specify the region, and sometimes the availability zones, i.e. for EC2 or RDS instances.
We provision resources in multiple availability zones to avoid unexpected downtime in case of Availability Zone outages.
In order to get the Availability Zones in CDK we have to use the availabilityZones property on the core Stack construct.
import * as cdk from 'aws-cdk-lib'; export class MyCdkStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props: cdk.StackProps) { super(scope, id, props); // ๐ get Availability Zones, Region, Account console.log('availability zones ๐', cdk.Stack.of(this).availabilityZones); console.log('region ๐', cdk.Stack.of(this).region); console.log('accountId ๐', cdk.Stack.of(this).account); } } const app = new cdk.App(); new MyCdkStack(app, 'my-cdk-stack', { stackName: 'my-cdk-stack', // ๐ Set the environment for the stack env: { region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT, }, });
In the code sample:
We used the availabilityZones property on the Stack construct in order to get access to the availability zones of the region our CDK application is configured for.
We set the env property when instantiating our CDK stack. This sets the
environment (account, region), where our CDK stack will be deployed.
I'll issue the synth command to run my CDK code and print the values for the
Availability Zones and region.
npx aws-cdk synth
The output shows all of the Availability Zones for my default region -
eu-central-1.

If you get dummy values the first time you run the command, simply re-run
npx aws-cdk synth.
However, there are a couple of caveats with setting environments in CDK.
Every CDK stack we deploy belongs to a specific region and account. If
we don't explicitly set the region and account using the env property when
instantiating the stack, the stack is considered environment agnostic.
To better illustrate this scenario I'll comment out the env prop I've passed
to the stack upon instantiation:
import * as cdk from 'aws-cdk-lib'; export class MyCdkStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props: cdk.StackProps) { super(scope, id, props); // ๐ accessing the same values console.log('availability zones ๐', cdk.Stack.of(this).availabilityZones); console.log('region ๐', cdk.Stack.of(this).region); console.log('accountId ๐', cdk.Stack.of(this).account); } } const app = new cdk.App(); new MyCdkStack(app, 'my-cdk-stack', { stackName: 'my-cdk-stack', // โ๏ธ NOT setting env // env: { // region: process.env.CDK_DEFAULT_REGION, // account: process.env.CDK_DEFAULT_ACCOUNT, // }, });
I'll now issue the synth command to run my CDK code and print the outputs.
npx aws-cdk synth
The result shows the values as Tokens:

Tokens in CDK are encoded values that get resolved at deployment time by CloudFormation. This means we can't access the resolved version of these values in our CDK code, i.e. in conditional statements.
The reason we're getting token values back is that we haven't set the env
property upon stack instantiation, which makes our stack environment-agnostic.
Environment-agnostic stacks resolve the values of region, account and
availability zones at deployment time, rather than synthesis time. This means
that we don't have access to the resolved values in our CDK code.
In the screenshot we can see only 2 Availability Zones, the reason being - there are AWS regions that only provide 2 availability zones and CDK doesn't know if we'll be deploying to one of them. The safe bet on CDK's part is to just allow us to use 2 Availability Zones.
The account and region in an environment-agnostic stack get resolved to the
account and region of the profile we've set using the --profile flag, for
example:
npx aws-cdk deploy --profile my-profile
If we don't explicitly set the --profile flag the account and region values
are resolved to the default AWS CLI profile's account and region:
npx aws-cdk deploy
In order to get access to all of the Availability Zones of a region, the best
practice is to explicitly specify the env property when instantiating a stack.
const app = new cdk.App(); new MyCdkStack(app, 'my-cdk-stack', { stackName: 'my-cdk-stack', // ๐ explicitly set Env env: { region: 'us-east-1', account: '123456789', }, });
By doing that we are able to set a consistent environment for our stack deployments, regardless of the machine we're deploying from.
Now we can get access to all of the Availability Zones for the region our stack is configured for.
An alternative approach is to use the environment variables that CDK provides for us, i.e.:
const app = new cdk.App(); new MyCdkStack(app, 'my-cdk-stack', { stackName: 'my-cdk-stack', // ๐ Implicitly set env env: { region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT, }, });
The CDK_DEFAULT_REGION and CDK_DEFAULT_ACCOUNT
environment variables are made available
for us in the CDK environment. They resolve at synthesis time, which means we
are able to access all of the Availability Zones for the region.
However, they rely on behavior specific to local machine configuration:
if we don't pass a --profile flag when issuing the deploy command, these
environment variables resolve (at synthesis time) to our default AWS Profile's
account and region.
if we provide the --profile flag when deploying, the environment variables
are set to the profile's account and region at synthesis time.
The problem with this behavior is that local profile configuration may vary between your machine and the machines of other developers on your team, which might lead to deploying the CDK Stack to multiple accounts and regions.
To access the availability zones of an AWS region we have to:
env property when instantiating the CDK stackYou can learn more about the related topics by checking out the following tutorials: