2.4. Outputs and References

This lab covers pulumi.Output — how to inspect, transform with apply(), and combine outputs with Output.all().

Step 1 — Inspect stack outputs

The container from the previous lab already exports container_name. List all exported values for the current stack:

pulumi stack output

Read a single output by name:

pulumi stack output container_name

Explanation

pulumi.export("key", value) declares a stack output — a named value that is written to state after every successful deploy. Stack outputs are the public interface of a stack:

Where they appearHow
CLIpulumi stack output [name]
Other stacksConsumed via pulumi.StackReference
CI/CD scriptsRead with pulumi stack output --json for machine parsing

Outputs can also expose generated secrets to the console after a deploy — though in production, credentials belong in a dedicated store such as Azure Key Vault or HashiCorp Vault rather than as plain stack outputs.


Step 2 — Transform an output with apply()

Add a message export that embeds the container name into a string. Extend the main() function in __main__.py:

message = container.name.apply(
    lambda name: f"Container '{name}' is running — curl http://localhost:8080"
)
pulumi.export("message", message)

Apply and read the result:

pulumi up
pulumi stack output message

Explanation

container.name is not a plain str — it is a pulumi.Output[str]. Pulumi outputs are resolved asynchronously during deployment. At the time your Python module is evaluated, the container does not exist yet, so its name is not yet known. This shows up clearly in pulumi preview, where unresolved values appear as <computed>.

apply() schedules a function to run after the value is resolved at deploy time:

container.name ──(resolved)──► lambda name: f"..." ──► Output[str]

The return value of apply() is itself an Output, so it can be exported, passed into another resource argument, or chained with another apply().

Don’t use Output values directly as strings

This will raise a TypeError at runtime:

url = "http://localhost:8080/" + container.name  # Output[str] is not str

Always use apply() to work with the value inside an output.


Step 3 — Combine outputs with Output.all()

Export a single string that combines values from two different resources. Add to main():

summary = pulumi.Output.all(container.name, image.name).apply(
    lambda args: f"[{args[0]}] running image: {args[1]}"
)
pulumi.export("summary", summary)

Apply and inspect:

pulumi up
pulumi stack output summary

Explanation

Output.all() accepts any number of outputs and returns a single Output[list] that resolves when every input is resolved. It takes a function — expressed here as a lambda — that receives the resolved values as a list in the same order they were passed to Output.all().

Use Output.all() whenever your transformation needs values from more than one resource. A typical real-world example is assembling a database connection string:

connection_string = pulumi.Output.all(server.fully_qualified_domain_name, db.name).apply(
    lambda args: f"postgresql://{args[0]}/{args[1]}"
)

The PostgreSQL server hostname and the database name come from two separate resources — Output.all() waits for both before building the string.

Output.all() preserves dependencies

The resulting output carries the combined dependencies of all its inputs. Pulumi will ensure all referenced resources are fully deployed before any resource that consumes the combined output.