Pulumi’s dependsOn option lets you explicitly tell Pulumi that one resource needs another to be created before it, bypassing Pulumi’s automatic dependency detection.

Let’s see this in action. Imagine you’re deploying a web application. You’ll need a database, and then a web server that connects to that database. Pulumi is usually smart enough to figure this out.

Here’s a Pulumi TypeScript program that creates an AWS RDS instance and then an EC2 instance:

import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";

// Create a database subnet group for RDS
const dbSubnetGroup = new aws.rds.SubnetGroup("app-db-subnet-group", {
    subnetIds: ["subnet-xxxxxxxxxxxxxxxxx", "subnet-yyyyyyyyyyyyyyyyy"], // Replace with your actual subnet IDs
});

// Create an RDS instance
const dbInstance = new aws.rds.Instance("app-db-instance", {
    allocatedStorage: 20,
    engine: "mysql",
    engineVersion: "8.0",
    instanceClass: "db.t3.micro",
    dbSubnetGroupName: dbSubnetGroup.id,
    username: "admin",
    password: "mysecurepassword", // In a real scenario, use a secret manager
    skipFinalSnapshot: true,
});

// Create a security group for the web server
const webServerSecurityGroup = new aws.ec2.SecurityGroup("web-server-sg", {
    description: "Allow inbound HTTP traffic",
    ingress: [
        { protocol: "tcp", fromPort: 80, toPort: 80, cidrBlocks: ["0.0.0.0/0"] },
    ],
});

// Create a web server instance
const webServer = new aws.ec2.Instance("app-web-server", {
    ami: "ami-0c55b159cbfafe1f0", // Example AMI for Amazon Linux 2
    instanceType: "t2.micro",
    securityGroups: [webServerSecurityGroup.name],
    // This is where we might explicitly declare a dependency if needed
    // dependsOn: [dbInstance], // We'll discuss this more
});

// Export the RDS endpoint and web server public IP
export const rdsEndpoint = dbInstance.endpoint;
export const webServerPublicIp = webServer.publicIp;

Pulumi’s engine analyzes the resource graph. It sees that webServer will likely need dbInstance’s endpoint to configure itself. It infers a dependency from webServer to dbInstance. This means Pulumi will create dbInstance before webServer.

However, sometimes this automatic inference isn’t enough, or you want to be absolutely explicit. This is where dependsOn comes in. It’s a property you can pass to a resource’s constructor, and it accepts an array of other resources.

Let’s say, for example, that the webServer resource also needed a specific subnet that was provisioned by dbSubnetGroup, but Pulumi couldn’t automatically detect this indirect link. You would add dependsOn like this:

// Create a web server instance
const webServer = new aws.ec2.Instance("app-web-server", {
    ami: "ami-0c55b159cbfafe1f0", // Example AMI for Amazon Linux 2
    instanceType: "t2.micro",
    securityGroups: [webServerSecurityGroup.name],
    // Explicitly declare dependency on the DB instance and its subnet group
    dependsOn: [dbInstance, dbSubnetGroup],
});

By adding dependsOn: [dbInstance, dbSubnetGroup], you are guaranteeing that dbInstance and dbSubnetGroup will be fully provisioned and available before Pulumi even attempts to create webServer. This is crucial when a resource’s configuration relies on the existence or output values of another resource, even if those outputs aren’t directly referenced in the resource’s properties. Pulumi uses this to build a more robust execution plan, ensuring that resources are created in the correct order to avoid race conditions or incomplete configurations.

The key insight is that dependsOn isn’t just about ordering; it’s about signaling intent to the Pulumi engine. You’re telling it, "No matter what, these things must be ready first." This is particularly useful in complex deployments where resources might interact in ways that are not immediately obvious from the code’s direct property references. For instance, if your webServer’s user data script fetched a configuration from a database instance that was created separately, Pulumi might not infer that dependency unless you explicitly state it.

The most surprising truth about dependsOn is that it can also be used to create dependencies on outputs of resources, not just the resources themselves. This is less common but powerful. If you had a resource otherResource whose output configValue was needed by webServer, you could write:

const webServer = new aws.ec2.Instance("app-web-server", {
    // ... other properties
    dependsOn: [otherResource.configValue], // Dependency on an output value
});

This tells Pulumi that webServer cannot start provisioning until otherResource has completed, and specifically, until its configValue output is ready. Pulumi’s engine is designed to handle this by ensuring the resource that produces the output is complete before the dependent resource begins. This allows for more granular control over the deployment flow, ensuring that all necessary prerequisites, even indirect ones, are met.

The next thing you’ll likely encounter is managing secrets and sensitive data across resources, especially when one resource’s output is a secret needed by another.

Want structured learning?

Take the full Pulumi course →