0
# Output System
1
2
Pulumi's Output system provides async value management with dependency tracking, enabling safe composition of promises and resource dependencies throughout infrastructure code. Outputs represent values that may not be available until deployment time.
3
4
## Core Output Types
5
6
```typescript { .api }
7
abstract class Output<T> {
8
apply<U>(func: (t: T) => Input<U>): Output<U>;
9
readonly isKnown: Promise<boolean>;
10
readonly isSecret: Promise<boolean>;
11
}
12
13
interface OutputInstance<T> extends Output<T> {
14
__pulumiOutput: true;
15
}
16
17
type Input<T> = T | Promise<T> | OutputInstance<T>;
18
type Inputs = Record<string, Input<any>>;
19
20
type Unwrap<T> = T extends OutputInstance<infer U> ? U :
21
T extends Promise<infer U> ? U : T;
22
23
type UnwrappedObject<T> = {
24
[K in keyof T]: Unwrap<T[K]>;
25
};
26
27
type Lifted<T> = {
28
[K in keyof T]: Output<T[K]>;
29
};
30
```
31
32
## Core Output Functions
33
34
```typescript { .api }
35
function output<T>(val: Input<T>): Output<Unwrap<T>>;
36
function secret<T>(val: Input<T>): Output<Unwrap<T>>;
37
function unsecret<T>(val: Input<T>): Output<Unwrap<T>>;
38
function isSecret<T>(val: Output<T>): Promise<boolean>;
39
40
function all<T>(values: T): Output<UnwrappedObject<T>>;
41
function concat(...params: Input<any>[]): Output<string>;
42
function interpolate(literals: TemplateStringsArray, ...placeholders: Input<any>[]): Output<string>;
43
44
function jsonStringify(val: Input<any>, replacer?: any, space?: Input<string | number>): Output<string>;
45
function jsonParse<T>(text: Input<string>, reviver?: any): Output<T>;
46
```
47
48
## Utility Functions
49
50
```typescript { .api }
51
function deferredOutput<T>(): { output: Output<T>; setter: (value: Input<T>) => void };
52
function getAllResources<T>(op: Output<T>): Resource[];
53
function isSecretOutput<T>(o: any): o is Output<T>;
54
function isUnknown(val: any): boolean;
55
function containsUnknowns(value: any): boolean;
56
```
57
58
## Error Classes
59
60
```typescript { .api }
61
class OutputToStringError extends Error {
62
constructor(message: string);
63
}
64
65
class Unknown {
66
readonly isKnown: false;
67
readonly isSecret: false;
68
}
69
```
70
71
## Usage Examples
72
73
### Basic Output Creation
74
75
```typescript
76
import * as pulumi from "@pulumi/pulumi";
77
78
// Create output from values
79
const simpleOutput = pulumi.output("hello");
80
const promiseOutput = pulumi.output(Promise.resolve(42));
81
82
// Create secret outputs
83
const secretOutput = pulumi.secret("my-secret-value");
84
const secretFromConfig = new pulumi.Config().requireSecret("apiKey");
85
```
86
87
### Output Transformation
88
89
```typescript
90
import * as pulumi from "@pulumi/pulumi";
91
92
const bucket = new aws.s3.Bucket("my-bucket");
93
94
// Transform a single output
95
const bucketUrl = bucket.id.apply(id => `https://${id}.s3.amazonaws.com`);
96
97
// Chain transformations
98
const processedName = bucket.id
99
.apply(id => id.toLowerCase())
100
.apply(id => id.replace(/-/g, "_"));
101
102
// Handle async transformations
103
const bucketSize = bucket.id.apply(async (id) => {
104
const response = await getBucketSize(id);
105
return response.size;
106
});
107
```
108
109
### Combining Multiple Outputs
110
111
```typescript
112
import * as pulumi from "@pulumi/pulumi";
113
114
const bucket = new aws.s3.Bucket("my-bucket");
115
const distribution = new aws.cloudfront.Distribution("cdn", {
116
// ... config
117
});
118
119
// Combine multiple outputs into object
120
const combined = pulumi.all({
121
bucketName: bucket.id,
122
distributionId: distribution.id,
123
region: aws.getRegion().then(r => r.name),
124
}).apply(({ bucketName, distributionId, region }) => ({
125
url: `https://${distributionId}.cloudfront.net`,
126
bucket: bucketName,
127
region: region,
128
}));
129
130
// Combine into array
131
const urls = pulumi.all([
132
bucket.websiteEndpoint,
133
distribution.domainName,
134
]).apply(([bucketUrl, cdnUrl]) => ({
135
direct: `http://${bucketUrl}`,
136
cdn: `https://${cdnUrl}`,
137
}));
138
```
139
140
### String Interpolation
141
142
```typescript
143
import * as pulumi from "@pulumi/pulumi";
144
145
const bucket = new aws.s3.Bucket("my-bucket");
146
const region = aws.getRegion();
147
148
// Template string interpolation
149
const bucketUrl = pulumi.interpolate`https://${bucket.id}.s3.${region.name}.amazonaws.com`;
150
151
// Complex interpolation
152
const configHtml = pulumi.interpolate`
153
<configuration>
154
<bucket>${bucket.id}</bucket>
155
<region>${region.name}</region>
156
<timestamp>${Date.now()}</timestamp>
157
</configuration>`;
158
```
159
160
### Concatenation
161
162
```typescript
163
import * as pulumi from "@pulumi/pulumi";
164
165
const prefix = pulumi.output("prod");
166
const suffix = pulumi.output("db");
167
168
// Simple concatenation
169
const resourceName = pulumi.concat(prefix, "-", suffix);
170
171
// With multiple inputs
172
const fullPath = pulumi.concat(
173
"/api/v1/",
174
prefix,
175
"/",
176
suffix,
177
"/config"
178
);
179
```
180
181
### JSON Operations
182
183
```typescript
184
import * as pulumi from "@pulumi/pulumi";
185
186
const config = pulumi.all({
187
database: {
188
host: "localhost",
189
port: 5432,
190
},
191
cache: {
192
host: "redis.example.com",
193
port: 6379,
194
},
195
});
196
197
// Convert to JSON string
198
const configJson = pulumi.jsonStringify(config, null, 2);
199
200
// Parse JSON string
201
const jsonString = pulumi.output('{"key": "value", "number": 42}');
202
const parsed = pulumi.jsonParse<{key: string; number: number}>(jsonString);
203
```
204
205
### Secret Handling
206
207
```typescript
208
import * as pulumi from "@pulumi/pulumi";
209
210
const config = new pulumi.Config();
211
const dbPassword = config.requireSecret("dbPassword");
212
213
// Check if output is secret
214
const isSecretCheck = pulumi.isSecret(dbPassword); // Promise<boolean>
215
216
// Combine secret with non-secret (result is secret)
217
const connectionString = pulumi.interpolate`postgresql://user:${dbPassword}@localhost:5432/mydb`;
218
219
// Remove secret marking (use carefully!)
220
const plainPassword = pulumi.unsecret(dbPassword);
221
```
222
223
### Deferred Outputs
224
225
```typescript
226
import * as pulumi from "@pulumi/pulumi";
227
228
// Create deferred output for complex initialization
229
const { output: deferredValue, setter: setValue } = pulumi.deferredOutput<string>();
230
231
// Set value later (perhaps after async operation)
232
async function initializeValue() {
233
const result = await someAsyncOperation();
234
setValue(result);
235
}
236
237
initializeValue();
238
239
// Use the deferred output
240
export const finalValue = deferredValue;
241
```
242
243
### Working with Unknown Values
244
245
```typescript
246
import * as pulumi from "@pulumi/pulumi";
247
248
// During preview, some values are unknown
249
const bucket = new aws.s3.Bucket("my-bucket");
250
251
bucket.id.apply(id => {
252
if (pulumi.isUnknown(id)) {
253
console.log("Bucket ID is unknown during preview");
254
return "preview-placeholder";
255
}
256
return `Bucket ID: ${id}`;
257
});
258
259
// Check for unknowns in complex objects
260
const configObject = {
261
bucketId: bucket.id,
262
region: "us-east-1"
263
};
264
265
if (pulumi.containsUnknowns(configObject)) {
266
console.log("Config contains unknown values");
267
}
268
```
269
270
### Resource Dependencies
271
272
```typescript
273
import * as pulumi from "@pulumi/pulumi";
274
275
const bucket = new aws.s3.Bucket("my-bucket");
276
277
// Get all resources that an output depends on
278
const dependencies = pulumi.getAllResources(bucket.id);
279
console.log(`Bucket ID depends on ${dependencies.length} resources`);
280
281
// Outputs automatically track dependencies
282
const bucketPolicy = new aws.s3.BucketPolicy("policy", {
283
bucket: bucket.id, // This creates a dependency
284
policy: bucket.arn.apply(arn => JSON.stringify({
285
Version: "2012-10-17",
286
Statement: [{
287
Effect: "Allow",
288
Principal: "*",
289
Action: "s3:GetObject",
290
Resource: `${arn}/*`
291
}]
292
}))
293
});
294
```
295
296
## Best Practices
297
298
- Use `apply()` for transforming single outputs
299
- Use `all()` for combining multiple outputs
300
- Use `interpolate` for string templates with outputs
301
- Mark sensitive data as secrets with `secret()`
302
- Handle unknown values gracefully in preview mode
303
- Avoid blocking operations in output transformations
304
- Chain transformations instead of nesting `apply()` calls
305
- Use TypeScript generics to maintain type safety through transformations