0
# Resource Management
1
2
Pulumi's resource management system provides the foundation for creating, managing, and organizing cloud infrastructure resources with automatic dependency tracking and lifecycle management.
3
4
## Core Resource Classes
5
6
```typescript { .api }
7
abstract class Resource {
8
readonly urn: Output<string>;
9
readonly __pulumiResource: boolean;
10
11
protected constructor(type: string, name: string, opts?: ResourceOptions);
12
}
13
14
class CustomResource extends Resource {
15
readonly id: Output<ID>;
16
readonly __pulumiCustomResource: boolean;
17
18
protected constructor(type: string, name: string, props?: any, opts?: CustomResourceOptions);
19
}
20
21
class ProviderResource extends CustomResource {
22
readonly pkg: string;
23
readonly __pulumiProviderResource: boolean;
24
25
protected constructor(pkg: string, name: string, props?: any, opts?: CustomResourceOptions);
26
}
27
28
class ComponentResource<TData = any> extends Resource {
29
readonly __pulumiComponentResource: boolean;
30
31
protected constructor(type: string, name: string, opts?: ComponentResourceOptions);
32
33
registerOutputs(outputs?: Inputs | Promise<Inputs> | Output<Inputs>): void;
34
}
35
```
36
37
## Resource Options
38
39
```typescript { .api }
40
interface ResourceOptions {
41
// Dependency management
42
dependsOn?: Input<Input<Resource>[]> | Input<Resource>;
43
parent?: Resource;
44
45
// Lifecycle options
46
protect?: boolean;
47
ignoreChanges?: string[];
48
deleteBeforeReplace?: boolean;
49
replaceOnChanges?: string[];
50
retainOnDelete?: boolean;
51
deletedWith?: Resource;
52
53
// Provider options
54
provider?: ProviderResource;
55
providers?: Record<string, ProviderResource>;
56
version?: string;
57
pluginDownloadURL?: string;
58
59
// Aliasing and transformation
60
aliases?: Input<Alias[]>;
61
customTimeouts?: CustomTimeouts;
62
transformations?: ResourceTransformation[];
63
transforms?: ResourceTransform[];
64
hooks?: ResourceHook[];
65
}
66
67
interface CustomResourceOptions extends ResourceOptions {
68
id?: Input<ID>;
69
import?: Input<string>;
70
importId?: Input<ID>;
71
}
72
73
interface ComponentResourceOptions extends ResourceOptions {
74
// ComponentResource-specific options
75
}
76
```
77
78
## Resource Lifecycle Types
79
80
```typescript { .api }
81
interface Alias {
82
name?: Input<string>;
83
type?: Input<string>;
84
parent?: Input<Resource>;
85
stack?: Input<string>;
86
project?: Input<string>;
87
}
88
89
interface CustomTimeouts {
90
create?: Input<string>;
91
update?: Input<string>;
92
delete?: Input<string>;
93
}
94
95
type ID = string;
96
type URN = string;
97
```
98
99
## Transformation System
100
101
```typescript { .api }
102
type ResourceTransform = (args: ResourceTransformArgs) => Promise<ResourceTransformResult | undefined> | ResourceTransformResult | undefined;
103
104
interface ResourceTransformArgs {
105
type: string;
106
name: string;
107
props: Inputs;
108
opts: ResourceOptions;
109
}
110
111
interface ResourceTransformResult {
112
props?: Inputs;
113
opts?: ResourceOptions;
114
}
115
116
// Legacy transformation system (deprecated)
117
type ResourceTransformation = (args: ResourceTransformationArgs) => Promise<ResourceTransformationResult | undefined> | ResourceTransformationResult | undefined;
118
```
119
120
## Hook System
121
122
```typescript { .api }
123
class ResourceHook {
124
constructor(options: ResourceHookOptions);
125
}
126
127
interface ResourceHookOptions {
128
before?: ResourceHookFunction;
129
after?: ResourceHookFunction;
130
}
131
132
type ResourceHookFunction = (args: ResourceHookArgs) => Promise<void> | void;
133
134
interface ResourceHookArgs {
135
type: string;
136
name: string;
137
props: Inputs;
138
opts: ResourceOptions;
139
resource: Resource;
140
}
141
```
142
143
## Utility Functions
144
145
```typescript { .api }
146
function createUrn(name: Input<string>, type: Input<string>, parent?: Resource, project?: string, stack?: string): Output<string>;
147
function allAliases(name: string, aliases: Input<Alias[]> | undefined, parent: Resource | undefined): Output<string>[];
148
function mergeOptions(opts1?: ResourceOptions, opts2?: ResourceOptions): ResourceOptions;
149
function parseResourceReference(ref: string): { urn: string; id?: string; packageVersion?: string };
150
function pkgFromType(type: string): string;
151
function resourceType(res: Resource): string;
152
function resourceName(res: Resource): string;
153
```
154
155
## Usage Examples
156
157
### Basic Resource Creation
158
159
```typescript
160
import * as pulumi from "@pulumi/pulumi";
161
import * as aws from "@pulumi/aws";
162
163
// Simple resource creation
164
const bucket = new aws.s3.Bucket("my-bucket", {
165
acl: "private",
166
versioning: {
167
enabled: true,
168
},
169
});
170
171
// Resource with explicit dependencies
172
const role = new aws.iam.Role("lambda-role", {
173
assumeRolePolicy: JSON.stringify({
174
Version: "2012-10-17",
175
Statement: [{
176
Effect: "Allow",
177
Principal: { Service: "lambda.amazonaws.com" },
178
Action: "sts:AssumeRole",
179
}],
180
}),
181
});
182
183
const lambda = new aws.lambda.Function("my-lambda", {
184
code: new pulumi.asset.AssetArchive({
185
".": new pulumi.asset.FileArchive("./lambda"),
186
}),
187
role: role.arn, // Automatic dependency
188
handler: "index.handler",
189
runtime: "nodejs18.x",
190
}, {
191
dependsOn: [role], // Explicit dependency
192
});
193
```
194
195
### Resource Options
196
197
```typescript
198
import * as pulumi from "@pulumi/pulumi";
199
import * as aws from "@pulumi/aws";
200
201
// Resource with comprehensive options
202
const database = new aws.rds.Instance("prod-db", {
203
engine: "postgres",
204
instanceClass: "db.t3.micro",
205
allocatedStorage: 20,
206
dbName: "myapp",
207
username: "admin",
208
password: new pulumi.Config().requireSecret("dbPassword"),
209
}, {
210
// Lifecycle protection
211
protect: true,
212
213
// Ignore changes to specific properties
214
ignoreChanges: ["password"],
215
216
// Custom timeout
217
customTimeouts: {
218
create: "30m",
219
update: "20m",
220
delete: "10m",
221
},
222
223
// Replace on specific property changes
224
replaceOnChanges: ["engine", "instanceClass"],
225
226
// Retain on delete
227
retainOnDelete: true,
228
});
229
```
230
231
### Component Resources
232
233
```typescript
234
import * as pulumi from "@pulumi/pulumi";
235
import * as aws from "@pulumi/aws";
236
237
interface WebsiteArgs {
238
domain: string;
239
indexContent: string;
240
}
241
242
class Website extends pulumi.ComponentResource {
243
public readonly bucketName: pulumi.Output<string>;
244
public readonly websiteUrl: pulumi.Output<string>;
245
246
constructor(name: string, args: WebsiteArgs, opts?: pulumi.ComponentResourceOptions) {
247
super("custom:Website", name, {}, opts);
248
249
// Create child resources
250
const bucket = new aws.s3.Bucket(`${name}-bucket`, {
251
website: {
252
indexDocument: "index.html",
253
},
254
}, { parent: this });
255
256
const indexObject = new aws.s3.BucketObject(`${name}-index`, {
257
bucket: bucket.id,
258
key: "index.html",
259
content: args.indexContent,
260
contentType: "text/html",
261
}, { parent: this });
262
263
// Set outputs
264
this.bucketName = bucket.id;
265
this.websiteUrl = bucket.websiteEndpoint;
266
267
// Register outputs for the component
268
this.registerOutputs({
269
bucketName: this.bucketName,
270
websiteUrl: this.websiteUrl,
271
});
272
}
273
}
274
275
// Use the component
276
const website = new Website("my-website", {
277
domain: "example.com",
278
indexContent: "<h1>Hello World</h1>",
279
});
280
```
281
282
### Resource Transformations
283
284
```typescript
285
import * as pulumi from "@pulumi/pulumi";
286
import * as aws from "@pulumi/aws";
287
288
// Global transformation to add common tags
289
const addCommonTags: pulumi.ResourceTransform = (args) => {
290
if (args.type.startsWith("aws:")) {
291
return {
292
props: {
293
...args.props,
294
tags: {
295
...args.props.tags,
296
Environment: "production",
297
ManagedBy: "pulumi",
298
Project: pulumi.getProject(),
299
},
300
},
301
opts: args.opts,
302
};
303
}
304
return undefined;
305
};
306
307
// Apply transformation to specific resources
308
const bucket = new aws.s3.Bucket("my-bucket", {
309
acl: "private",
310
}, {
311
transforms: [addCommonTags],
312
});
313
314
// Or apply globally via stack options
315
const stack = new pulumi.ComponentResource("MyStack", "my-stack", {}, {
316
transforms: [addCommonTags],
317
});
318
```
319
320
### Resource Hooks
321
322
```typescript
323
import * as pulumi from "@pulumi/pulumi";
324
325
// Create hooks for monitoring resource creation
326
const loggingHook = new pulumi.ResourceHook({
327
before: (args) => {
328
console.log(`Creating resource: ${args.type}:${args.name}`);
329
},
330
after: (args) => {
331
console.log(`Created resource: ${args.type}:${args.name}`);
332
},
333
});
334
335
const bucket = new aws.s3.Bucket("my-bucket", {
336
acl: "private",
337
}, {
338
hooks: [loggingHook],
339
});
340
```
341
342
### Resource Aliases
343
344
```typescript
345
import * as pulumi from "@pulumi/pulumi";
346
import * as aws from "@pulumi/aws";
347
348
// Handle resource renames with aliases
349
const bucket = new aws.s3.Bucket("my-new-bucket", {
350
acl: "private",
351
}, {
352
aliases: [
353
{ name: "my-old-bucket" },
354
{ name: "my-very-old-bucket", type: "aws:s3/bucket:Bucket" },
355
],
356
});
357
```
358
359
### Resource Import
360
361
```typescript
362
import * as pulumi from "@pulumi/pulumi";
363
import * as aws from "@pulumi/aws";
364
365
// Import existing resource
366
const existingBucket = new aws.s3.Bucket("imported-bucket", {
367
// Properties must match existing resource
368
acl: "private",
369
versioning: {
370
enabled: false,
371
},
372
}, {
373
import: "existing-bucket-name",
374
});
375
```
376
377
### Advanced Dependency Management
378
379
```typescript
380
import * as pulumi from "@pulumi/pulumi";
381
import * as aws from "@pulumi/aws";
382
383
const vpc = new aws.ec2.Vpc("main-vpc", {
384
cidrBlock: "10.0.0.0/16",
385
});
386
387
const subnet = new aws.ec2.Subnet("main-subnet", {
388
vpcId: vpc.id,
389
cidrBlock: "10.0.1.0/24",
390
});
391
392
const securityGroup = new aws.ec2.SecurityGroup("web-sg", {
393
vpcId: vpc.id,
394
ingress: [{
395
fromPort: 80,
396
toPort: 80,
397
protocol: "tcp",
398
cidrBlocks: ["0.0.0.0/0"],
399
}],
400
});
401
402
// Resource with multiple dependencies
403
const instance = new aws.ec2.Instance("web-server", {
404
ami: "ami-12345678",
405
instanceType: "t3.micro",
406
subnetId: subnet.id,
407
vpcSecurityGroupIds: [securityGroup.id],
408
}, {
409
// Explicit additional dependencies
410
dependsOn: [vpc], // Even though implicit via subnet
411
412
// Delete this resource with the VPC
413
deletedWith: vpc,
414
});
415
```
416
417
## Best Practices
418
419
- Use component resources to create reusable infrastructure patterns
420
- Leverage automatic dependency tracking through resource references
421
- Use explicit `dependsOn` only when implicit dependencies aren't sufficient
422
- Protect critical resources with the `protect` option
423
- Use aliases when renaming or restructuring resources
424
- Apply transformations for consistent resource configuration
425
- Use custom timeouts for long-running operations
426
- Consider `replaceOnChanges` for properties that require replacement
427
- Use `retainOnDelete` for resources that should persist after stack deletion