CoursesPulumiIntermediate

Inputs, Outputs & apply

The async value model that trips everyone.

Intermediate14 min · lesson 5 of 12

The one concept that trips every Pulumi newcomer is Inputs and Outputs. Many resource attributes are not known until the resource is actually created — an ARN, an assigned IP, a generated ID. Pulumi models these as Output<T>: a value that will exist after deployment, not during program execution. You cannot treat an Output like a plain string, because at the moment your code runs, the real value does not exist yet.

OUTPUT LIFECYCLE
1Construct resource
program runs; arn/id not known yet
2Attribute is Output<T>
using it as a string prints 'Calculating...'
3apply / interpolate / all
schedule the transform for after deploy
4Resolves post-deploy
function runs, returns a new Output
5Export or feed to resource
downstream value is also an Output
Anything touching an Output stays an Output until you export it or feed it into another resource.
index.ts
const bucket = new aws.s3.BucketV2("logs", {});
// WRONG: bucket.arn is an Output<string>, not a string
// const msg = "ARN is " + bucket.arn; // => "ARN is Calculating..."
// RIGHT: transform the value once it exists
const msg = bucket.arn.apply(arn => `ARN is ${arn}`);
// or interpolate several Outputs:
export const url = pulumi.interpolate`https://${bucket.bucketDomainName}`;

apply, interpolate, all

Three tools cover almost every case. apply(fn) runs your function once the Output resolves and returns a new Output. pulumi.interpolate is a template string that understands Outputs. pulumi.all([...]) waits for several Outputs together so you can combine them. The mental rule: once a value is an Output, everything downstream that touches it is also an Output until you export it or feed it into another resource.

index.ts
const combined = pulumi
.all([bucket.arn, queue.url])
.apply(([arn, url]) => buildPolicyJson(arn, url)); // both resolved together
Do not stringify an Output
Concatenating or template-stringing an Output with plain JS gives you “Calculating...” or [object Object], not the value — the classic first-day bug. Anything that needs the real value must go through apply, interpolate, or all. If a resource argument “isn’t taking” your computed value, it is almost always an Output used as if it were a string.