Skip to main content
The stack block is the primary declaration in XCL. It contains resource bindings that become Pulumi resources when compiled.

Syntax

stack "name" {
    // resource bindings
}
A stack directory may span multiple .xcl files. All stack blocks across all files in the directory are merged into a single compilation unit. The name label is for documentation only — the actual Pulumi project name is taken from the directory name.

Named resource binding

stack "networking" {
    vpc = aws.ec2.Vpc {
        cidr_block = input.vpc_cidr
        tags = {
            Name = "my-vpc"
        }
    }
}
vpc is the binding name — used throughout the stack to reference this resource’s outputs (e.g., vpc.id). The type path aws.ec2.Vpc maps directly to the Pulumi provider class. The provider segment (aws) determines which pulumi_aws package is imported.

Unnamed (fire-and-forget) resources

A resource without a binding name runs but its outputs cannot be referenced:
stack "bootstrap" {
    aws.iam.RolePolicy {
        role   = input.role_name
        policy = input.policy_doc
    }
}

For clause — iterating over a collection

stack "networking" {
    subnets = aws.ec2.Subnet {
        for az in input.azs

        vpc_id            = vpc.id
        availability_zone = az
    }
}
The for clause creates one resource per element of the collection. Inside the block, az (or whichever variable name you choose) refers to the current element. For maps, use the key-value form:
bucket_policies = aws.s3.BucketPolicy {
    for name, config in input.buckets

    bucket = name
    policy = config.policy
}

Count modifier — creating N identical resources

stack "networking" {
    subnets = aws.ec2.Subnet * 3 {
        for idx in input.azs

        vpc_id     = vpc.id
        cidr_block = "10.0.0.0/16"
    }
}
The * N modifier (where N is any expression) is combined with a for clause. It specifies how many resources to create.

When clause — conditional resources

stack "networking" {
    nat = aws.ec2.NatGateway when input.deploy_nat {
        subnet_id = subnets.id
    }
}
The when condition must be a Resolved value — an input field or a locals value. It cannot reference resource outputs (which are Pending<T> and only known after apply). Error if you use a resource output:
when condition references "vpc" which is Pending<T> (a resource output) — when conditions must be Resolved<T> (use an input or locals value instead)

Referencing resource outputs

After a resource is declared, its outputs are available as resourceName.outputName:
stack "networking" {
    vpc = aws.ec2.Vpc {
        cidr_block = input.vpc_cidr
    }

    subnet = aws.ec2.Subnet {
        vpc_id = vpc.id  // references the vpc resource's id output
    }
}
Resource outputs are Pending — they are only resolved after the cloud deployment completes. This means you cannot use them in when conditions.

Referencing for-resource outputs

When a resource is created with a for clause, referencing it produces a list:
output "networking" {
    subnet_ids = subnets.id  // list of all subnet IDs
}
In generated Python this becomes a list comprehension: [r.id for r in subnets].

Cross-stack references

Use @stackName.outputName to reference an output from a sibling stack:
stack "cluster" {
    eks = aws.eks.Cluster {
        vpc_id     = @networking.vpc_id
        subnet_ids = @networking.subnet_ids
    }
}
The sibling stack must be in a directory adjacent to the current stack’s parent. See Multi-stack workspaces for details.

Match and ternary in resource properties

Match expressions and ternary expressions are not allowed directly in resource properties. Move them to a locals block first:
// Error:
stack "s" {
    bucket = aws.s3.Bucket {
        acl = "public" if input.is_public else "private"  // not allowed here
    }
}

// Correct:
locals "s" {
    bucket_acl = "public" if input.is_public else "private"
}

stack "s" {
    bucket = aws.s3.Bucket {
        acl = locals.bucket_acl
    }
}
Error message: conditional (if/else) expressions are not allowed in resource properties — move this expression into a locals block

Multiple stack blocks

A stack can be spread across files. All stack "name" { ... } blocks in the directory are merged, and resource names must be unique across all files. Error for duplicate resource names: "vpc" is already defined in stack.xcl:3 - remove one, or rename