← Back to list

AWS CDK and cdk.context.json — how to use it correctly?

AWS CDK has a set of best practices that serve as a guide to efficient use of CDK. There is also a set of best practices for AWS…

Bernard Orzechowski in qoob.dev · 2024-05-20 18:36 · 4 claps · 4.0 min read
#aws #aws-cdk #aws-cloudformation #infrastructure-from-code #infrastructure-as-code
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud

AWS CDK and cdk.context.json — how to use it correctly?

AWS CDK has a set of best practices that serve as a guide to efficient use of CDK. There is also a set of best practices for AWS CloudFormation. Since your CDK code will ultimately be transformed into CloudFormation templates, it is important to consider both for optimal setup.

In this article I will describe a quite often overlooked aspect of using the cdk.context.json file, namely how to guarantee that cdk synth isn't running a double synthesis. Which besides the determinism of synthesis impacts also negatively the execution time of cdk deployments.

CDK best practice — Commit cdk.context.json to avoid non-deterministic behavior

This recommendation can be found in the application best practices section in AWS docs.

The cdk.context.json file is used as one (out of six) of the sources of cdk context values. What is so special about it is the fact that it caches the values that would be otherwise returned from AWS Account which is also a source of context values. The huge disadvantage of getting the context values from AWS Account is that the cdk synth command is internally being executed twice to provide the resulting AWS CloudFormation templates.

Hence the cdk.context.json is important for 2 reasons:

  • to have deterministic deployments
  • to run CDK synthesis in optimal time (one synthesis run) instead of a double

We will focus more on the latter one as it is very important in large projects where:

  • there are many deployments (CI/CD pipelines or at least cdk synth done locally by developers) and / or
  • each cdk synth takes some time e.g. due to some internal processing

As developers we want to have fast pipelines and cdk synth results.

Impact on cdk synth — example

The below sample code will:

  • at first run as expected without any double synthesis
  • but then we will introduce a call (even its a read only call) to AWS Infrastructure that will trigger the double cdk synth
  • as a side effect the cdk.context.json file will be generated. Being there the next cdk synth will behave again as expected

Lets first take a look at the sample cdk app with one stack (NoContextValueUsedStack).

#!/usr/bin/env python3
import os

import aws_cdk as cdk
from hello_cdk.cdk_context_example import NoContextValueUsedStack  # noqa: E501

app = cdk.App()

stack_with_no_context_value_used = NoContextValueUsedStack(
    app,
    "StackWithNoContextValueUsed",
    env=cdk.Environment(
        account=os.getenv("CDK_DEFAULT_ACCOUNT"),
        region=os.getenv("CDK_DEFAULT_REGION"),
    ),
)

print("Running cdk synthesis")

app.synth()

If we run cdk synththen:

  • “Running cdk synthesis” will be displayed once
  • cdk.context.json will not be created
(cdk-sample-py3.10) bernard@LAPTOP-DE588SCR:~/projects/cdk_sample/cdk_sample/hello-cdk$ cdk synth --quiet
Running cdk synthesis

Also no file cdk.context.json was generated.

(cdk-sample-py3.10) bernard@LAPTOP-DE588SCR:~/projects/cdk_sample/cdk_sample/hello-cdk$ ls -l | grep "cdk\.context\.json"
(cdk-sample-py3.10) bernard@LAPTOP-DE588SCR:~/projects/cdk_sample/cdk_sample/hello-cdk$ 

Example stacks — one ( ContextValueUsedStack ) that uses context lookup in the form of self.availability_zones as one of the methods listed here.

import aws_cdk as cdk
import aws_cdk.aws_s3 as s3

class NoContextValueUsedStack(cdk.Stack):
    def __init__(self, scope: cdk.App, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        s3.Bucket(self, "MyFirstBucket", versioned=True)

class ContextValueUsedStack(cdk.Stack):
    def __init__(self, scope: cdk.App, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        s3.Bucket(self, "MySecondBucket", versioned=True)
        self.availability_zones # HERE we use one of the context lookup methods

Lets now modify the sample cdk app and add the 2nd stack (ContextValueUsedStack).

#!/usr/bin/env python3
import os

import aws_cdk as cdk
from hello_cdk.cdk_context_example import ContextValueUsedStack  # noqa: E501
from hello_cdk.cdk_context_example import NoContextValueUsedStack  # noqa: E501

app = cdk.App()

stack_with_no_context_value_used = NoContextValueUsedStack(
    app,
    "StackWithNoContextValueUsed",
    env=cdk.Environment(
        account=os.getenv("CDK_DEFAULT_ACCOUNT"),
        region=os.getenv("CDK_DEFAULT_REGION"),
    ),
)

stack_with_context_value_used = ContextValueUsedStack(
    app,
    "StackWithContextValueUsed",
    env=cdk.Environment(
        account=os.getenv("CDK_DEFAULT_ACCOUNT"),
        region=os.getenv("CDK_DEFAULT_REGION"),
    ),
)

print("Running cdk synthesis")

app.synth()

If we run cdk synth then:

  • “Running cdk synthesis” will be displayed twice
  • cdk.context.json will be created
(cdk-sample-py3.10) bernard@LAPTOP-DE588SCR:~/projects/cdk_sample/cdk_sample/hello-cdk$ cdk synth --quiet
Running cdk synthesis
Running cdk synthesis
Successfully synthesized to /home/bernard/projects/cdk_sample/cdk_sample/hello-cdk/cdk.out
Supply a stack id (StackWithNoContextValueUsed, StackWithContextValueUsed) to display its template.

File cdk.context.json was created.

(cdk-sample-py3.10) bernard@LAPTOP-DE588SCR:~/projects/cdk_sample/cdk_sample/hello-cdk$ ls -l | grep "cdk\.context\.json"
-rw-r--r-- 1 bernard bernard  137 May 18 13:55 cdk.context.json
(cdk-sample-py3.10) bernard@LAPTOP-DE588SCR:~/projects/cdk_sample/cdk_sample/hello-cdk$

At this point we should store in git cdk.context.json file - if we want that our CI/CD pipelines will leverage this file. The assumption is that our CI/CD environment uses clean docker images to download the code and run the deployment.

As will be shown below this is still not enough to prevent double synthesis from (accidental) happening. If we want to be 100% sure, we need to do more.

How to recognize that double synthesis is happening?

There are 2 ways — the bad one presented above done through some form of logging. Note that when there is no logging happening then its impossible to observe.

This method has an additional problem. Even if at some point in time we double checked that cdk synthesis is done only once, what if there is a change in imported resource that was introduced afterwards — e.g. a developer added a new stack which uses some form of resource lookup leading to double synth? Can we prevent it?

The answer is yes. The correct 2nd way of doing it. There is a parameter --lookups (which unfortunately has a default value of true) that we can use to fail a synthesis if a lookup is needed.

(cdk-sample-py3.10) bernard@LAPTOP-DE588SCR:~/projects/cdk_sample/cdk_sample/hello-cdk$ cdk synth --help
cdk synthesize [STACKS..]

Synthesizes and prints the CloudFormation template for this stack

Options:
  -a, --app                REQUIRED WHEN RUNNING APP: command-line for executing
                           your app or a cloud assembly directory (e.g. "node
                           bin/my-app.js"). Can also be specified in cdk.json or
                           ~/.cdk.json                                  [string]
...
      --lookups            Perform context lookups (synthesis fails if this is
                           disabled and context lookups need to be performed)
                                                       [boolean] [default: true]
...

Lets run our previous example with this option.

(cdk-sample-py3.10) bernard@LAPTOP-DE588SCR:~/projects/cdk_sample/cdk_sample/hello-cdk$ cdk synth --quiet --lookups false
Running cdk synthesis

Context lookups have been disabled. Make sure all necessary context is already in 'cdk.context.json' by running 'cdk synth' on a machine with sufficient AWS credentials and committing the result. Missing context keys: 'availability-zones:account=139497713478:region=eu-central-1'

As seen cdk synth failed.

Closing thoughts

To have constantly efficient cdk synth and prevent accidental changes in behavior of cdk synth please follow these simple steps:

  • store in git cdk.context.json
  • run cdk synth in your pipelines and locally with the option --lookups false

If you don’t implement the 2nd step, then even that you have cdk.context.json in git, a double cdk synth can happen.

Have a great day.


메타데이터
post_id
e1f5214514a9
slug
aws-cdk-and-cdk-context-json-how-to-use-it-correctly-e1f5214514a9
url
https://medium.com/qoob-dev/aws-cdk-and-cdk-context-json-how-to-use-it-correctly-e1f5214514a9
canonical_url
https://medium.com/qoob-dev/aws-cdk-and-cdk-context-json-how-to-use-it-correctly-e1f5214514a9
author_url
https://medium.com/@bernard.orzechowski
status
ok
fetched_at
2026-07-21 10:10:43