Skip to main content
for_each and count let you create multiple resources from a single block. when is the complement: it lets you skip a resource entirely when a condition is false. A replica bucket that only exists in prod. An audit log bucket gated on a feature flag. A monitoring endpoint disabled in dev to save costs. Without when, you’d need a separate stack file per environment or a count = condition ? 1 : 0 hack borrowed from Terraform. when makes the intent explicit — this resource is conditionally present, and the condition is right there on the block. When when is false, ubx generates no code for that resource at all. It doesn’t exist in state, it doesn’t get planned, and no apply-time logic is needed to skip it.

What you’ll learn

  • How when = condition conditionally creates or skips a resource
  • How to gate resources on environment, boolean inputs, or any resolved expression
  • How when = false differs from count = 0

Why this matters

when is evaluated at compile time — if the condition is false, the resource is entirely absent from the generated code. This is different from count = 0, which still registers the resource type with Pulumi. when produces genuinely absent resources with no state entry and no API calls.

The source code

# This bucket always exists.
unit "aws_s3_bucket_v2" "app" {
  bucket = "myapp-${input.env}"
}

# when = condition — the resource is only created when the condition is true.
# In dev/staging, the replica bucket is skipped. In prod, it is created.
unit "aws_s3_bucket_v2" "replica" {
  when   = input.env == "prod"
  bucket = "myapp-${input.env}-replica"

  tags = {
    ReplicaOf = "myapp-${input.env}"
  }
}

# when based on a bool input — enable via --var enable_audit_log=true.
unit "aws_s3_bucket_v2" "audit_log" {
  when   = input.enable_audit_log
  bucket = "myapp-${input.env}-audit"

  tags = {
    Purpose = "audit-logging"
  }
}

How it works

1

when is evaluated at compile time

input.env == "prod" is Resolved<T> — the compiler evaluates it against the resolved input value before generating code. If it evaluates to false, the entire unit block is removed from the IR.
2

False means absent, not empty

When when = false, the resource produces no output in the generated TypeScript/Python/Go. It doesn’t appear in the Pulumi resource graph, doesn’t get a state entry, and doesn’t generate any API calls.
3

References to conditional resources are checked

If another block references a resource that has when = false, the compiler raises a compile error — you cannot reference something that conditionally doesn’t exist. This catches broken references before they reach Pulumi.

What ubx generates

// Generated by ubx — do not edit
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const config = new pulumi.Config();
const env = config.get("env") || "dev";
const enableAuditLog = config.getBoolean("enableAuditLog") ?? false;

const app = new aws.s3.BucketV2("app", { bucket: `myapp-${env}` });

const replica = env === "prod"
    ? new aws.s3.BucketV2("replica", {
        bucket: `myapp-${env}-replica`,
        tags: { ReplicaOf: `myapp-${env}` },
    }) : undefined;

const auditLog = enableAuditLog
    ? new aws.s3.BucketV2("audit_log", {
        bucket: `myapp-${env}-audit`,
        tags: { Purpose: "audit-logging" },
    }) : undefined;

export const appBucket = app.bucket;

Common mistakes

Referencing a when-gated resource from another block without the same condition causes a compile error in stacks where the resource doesn’t exist. If unit.aws_s3_bucket_v2.replica only exists in prod, any output or deploy block referencing unit.aws_s3_bucket_v2.replica.bucket must also have when = input.env == "prod".
when composes naturally with for_each and count. A resource can have both — if when is false, no copies are created regardless of the for_each value.

Run it

ubx validate
ubx plan                                             # dev: only app bucket
ubx plan --var env=prod                              # prod: app + replica
ubx plan --var enable_audit_log=true                 # dev: app + audit
ubx plan --var env=prod --var enable_audit_log=true  # all three

What you learned

when = condition skips a resource entirely when false — no state entry, no API calls, no generated code
when is evaluated at compile time against resolved input values
Referencing a when-gated resource requires the same condition on the referencing block

Next steps

Lifecycle block

prevent_destroy, ignore_changes, create_before_destroy

Conditional expressions

if/else, ??, and nested conditions