CloudFormation’s DependsOn attribute, while seemingly straightforward, often trips people up because its primary purpose isn’t guaranteeing a specific creation order, but rather signaling a dependency that CloudFormation’s scheduler tries to honor.

Let’s watch this in action. Imagine you have two resources: a VPC and a subnet. You want the subnet to be created after the VPC.

Resources:
  MyVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16

  MySubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      CidrBlock: 10.0.1.0/24

In this example, MySubnet implicitly depends on MyVPC because it references !Ref MyVPC. CloudFormation’s scheduler is smart enough to figure this out. It sees that MySubnet needs the VpcId from MyVPC, so it won’t even try to create MySubnet until MyVPC is successfully provisioned. This implicit dependency is the most common way dependencies are handled, and DependsOn is often only needed for more complex, non-obvious relationships.

Now, let’s consider a scenario where DependsOn becomes explicitly necessary, or at least helpful for clarity. Suppose you’re creating an IAM Role and an IAM Policy, and then attaching that policy to the role. The attachment resource definitely needs both the role and the policy to exist.

Resources:
  MyRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
      Path: "/"

  MyPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action:
              - "s3:ListBucket"
            Resource: "*"
      PolicyName: MyS3ListPolicy
      Roles:
        - !Ref MyRole

  MyRolePolicyAttachment:
    Type: AWS::IAM::RolePolicyAttachment
    Properties:
      PolicyArn: !GetAtt MyPolicy.Arn
      RoleName: !Ref MyRole
    DependsOn: # Explicitly state dependencies for clarity, though often implied
      - MyRole
      - MyPolicy

Here, MyPolicy has a Roles property that references MyRole. This creates an implicit dependency. Similarly, MyRolePolicyAttachment references both MyRole and MyPolicy. CloudFormation’s scheduler will detect these. However, explicitly adding DependsOn can make the template more readable and can be crucial in situations where the dependency isn’t directly expressed through a property reference, such as when you need one resource to be created before another resource starts a process that doesn’t directly consume the first resource’s ID.

The most common cause of DependsOn confusion is believing it forces an order when CloudFormation has other options. CloudFormation’s scheduler is designed to parallelize resource creation as much as possible. If two resources don’t have a dependency, it will try to create them at the same time. DependsOn is a signal to the scheduler: "Don’t even consider creating me until these other things are done." It’s not a command to create them in a specific sequence among themselves, but rather a prerequisite for the dependent resource.

Here are the common pitfalls and how to diagnose them:

  1. Implicit Dependencies Not Recognized:

    • Diagnosis: You see an error like An error occurred (InvalidParameterValue) when calling the CreateVpc operation: The VPC ID 'vpc-xxxxxxxxxxxxxxxxx' does not exist. This means your subnet or other resource tried to use a VPC ID that CloudFormation hadn’t created yet. Check if a !Ref or !GetAtt in the dependent resource’s properties points to the resource that is supposed to be created first.
    • Fix: Ensure all cross-resource references use !Ref or !GetAtt correctly. For example, VpcId: !Ref MyVPC.
    • Why it works: CloudFormation’s engine analyzes these intrinsic functions to build its dependency graph. If a resource property references another resource, it’s a direct signal of dependency.
  2. DependsOn Used for Ordering Siblings:

    • Diagnosis: You have ResourceA and ResourceB, neither directly referencing the other, but you want ResourceA to be created before ResourceB. You add DependsOn: [ResourceA] to ResourceB. You might still see them being created concurrently or in the "wrong" order if CloudFormation’s scheduler finds no other explicit or implicit dependencies. The error might be a generic InternalFailure or a resource-specific error indicating a prerequisite was missing.
    • Fix: If you truly need ResourceA to finish before ResourceB starts, and there’s no other logical link, you must use DependsOn on ResourceB to reference ResourceA. For example:
      Resources:
        ResourceA:
          Type: AWS::Some::Resource
          Properties:
            # ...
        ResourceB:
          Type: AWS::Another::Resource
          Properties:
            # ...
          DependsOn:
            - ResourceA
      
    • Why it works: This explicitly tells the scheduler that ResourceA must be in a CREATE_COMPLETE state before it can even begin the creation process for ResourceB.
  3. Circular Dependencies:

    • Diagnosis: CloudFormation will detect this during the change set creation or stack update and throw an error like The template is not valid. Circular dependency detected: ....
    • Fix: Review your DependsOn attributes and intrinsic function references. You need to break the cycle. This often involves rethinking your resource design or using a temporary resource that doesn’t have a circular relationship.
    • Why it works: CloudFormation’s graph algorithm detects that A depends on B, and B depends on A (directly or indirectly), meaning neither can ever be created.
  4. DependsOn for Resource Deletion Order:

    • Diagnosis: When deleting a stack, resources that depend on another resource are deleted before the resource they depend on. If you want a specific deletion order (e.g., delete a dependent resource after its parent), DependsOn doesn’t directly control deletion order.
    • Fix: DependsOn primarily influences creation order. For deletion order, you often need to ensure that the resource being deleted doesn’t have explicit or implicit dependencies on resources you want to keep. If you need a resource to be deleted last, you might need to remove its dependencies before initiating the stack deletion or use custom resources for complex deletion logic.
    • Why it works: CloudFormation’s default deletion order is the reverse of its creation order. If A depends on B for creation, B is deleted before A.
  5. DependsOn with Custom Resources:

    • Diagnosis: Custom resources are often used for complex logic or to manage resources not directly supported by CloudFormation. If a custom resource’s ServiceToken (the Lambda ARN) or other properties depend on a resource that isn’t ready, you’ll get errors from the Lambda function itself.
    • Fix: Ensure the custom resource definition correctly uses DependsOn to reference any resources it needs to access or use as input. For example, if your custom resource needs to write to an S3 bucket created in the same stack:
      Resources:
        MyBucket:
          Type: AWS::S3::Bucket
          Properties:
            BucketName: my-unique-bucket-name
        MyCustomResource:
          Type: Custom::MyHandler
          Properties:
            ServiceToken: !GetAtt MyLambdaFunction.Arn
            BucketName: !Ref MyBucket # Implicit dependency
          DependsOn: # Can also explicitly add MyBucket
            - MyBucket
      
    • Why it works: Similar to AWS resources, the custom resource’s creation is gated by the completion of its dependencies, ensuring the Lambda function has access to necessary information or resources.
  6. Incorrect Resource States:

    • Diagnosis: Sometimes, a resource might appear to be CREATE_COMPLETE in the CloudFormation console, but it’s not fully functional or ready for other resources to interact with it. This is rare for native AWS resources but can happen with complex services or custom resources. Errors might be intermittent or appear only after the stack is "complete."
    • Fix: For critical dependencies, consider adding a "wait condition" resource or a custom resource that performs a health check or a simple operation on the dependent resource before signaling success.
    • Why it works: This adds an extra layer of verification, ensuring the dependent resource is not just provisioned but also operational before proceeding.

The most common next error you’ll hit after meticulously fixing DependsOn issues is a subtle timing problem where a resource appears complete but isn’t fully initialized, leading to transient errors when subsequent resources try to interact with it.

Want structured learning?

Take the full Cloudformation course →