0
# Stack References
1
2
Stack references enable access to outputs from other Pulumi stacks, facilitating cross-stack dependencies and data sharing in multi-stack architectures.
3
4
## Core Stack Reference Class
5
6
```typescript { .api }
7
class StackReference extends CustomResource {
8
constructor(name: string, args: StackReferenceArgs, opts?: CustomResourceOptions);
9
10
// Output access methods
11
getOutput(name: Input<string>): Output<any>;
12
requireOutput(name: Input<string>): Output<any>;
13
getOutputDetails(name: Input<string>): Output<StackReferenceOutputDetails>;
14
15
// Synchronous access (non-secret values only)
16
getOutputValue(name: string): any;
17
requireOutputValue(name: string): any;
18
19
// Properties
20
readonly name: Output<string>;
21
readonly outputs: Output<{[name: string]: any}>;
22
readonly secretOutputNames: Output<string[]>;
23
}
24
25
interface StackReferenceArgs {
26
name: Input<string>;
27
}
28
29
interface StackReferenceOutputDetails {
30
value?: any;
31
secretValue?: any;
32
}
33
```
34
35
## Usage Examples
36
37
### Basic Stack Reference
38
39
```typescript
40
import * as pulumi from "@pulumi/pulumi";
41
42
// Reference another stack
43
const networkStack = new pulumi.StackReference("network-stack", {
44
name: "myorg/network-infrastructure/production",
45
});
46
47
// Access outputs from the referenced stack
48
const vpcId = networkStack.getOutput("vpcId");
49
const subnetIds = networkStack.getOutput("privateSubnetIds");
50
51
// Use referenced outputs in current stack
52
const database = new aws.rds.Instance("app-db", {
53
subnetGroupName: new aws.rds.SubnetGroup("db-subnet-group", {
54
subnetIds: subnetIds,
55
}).name,
56
vpcSecurityGroupIds: [networkStack.getOutput("databaseSecurityGroupId")],
57
// ... other properties
58
});
59
```
60
61
### Cross-Organization References
62
63
```typescript
64
import * as pulumi from "@pulumi/pulumi";
65
66
// Reference stack from different organization
67
const sharedInfra = new pulumi.StackReference("shared-infrastructure", {
68
name: "shared-org/common-infrastructure/production",
69
});
70
71
// Get shared resources
72
const sharedVpc = sharedInfra.getOutput("vpcId");
73
const sharedDnsZone = sharedInfra.getOutput("dnsZoneId");
74
75
// Use in current stack
76
const service = new aws.ecs.Service("app-service", {
77
cluster: sharedInfra.getOutput("ecsClusterId"),
78
taskDefinition: taskDefinition.arn,
79
subnets: sharedInfra.getOutput("privateSubnetIds"),
80
});
81
```
82
83
### Handling Secret Outputs
84
85
```typescript
86
import * as pulumi from "@pulumi/pulumi";
87
88
const dbStack = new pulumi.StackReference("database-stack", {
89
name: "myorg/database/production",
90
});
91
92
// Get secret output (returns Output<any>)
93
const dbPassword = dbStack.getOutput("masterPassword");
94
95
// Get output details to check if secret
96
const passwordDetails = dbStack.getOutputDetails("masterPassword");
97
98
passwordDetails.apply(details => {
99
if (details.secretValue !== undefined) {
100
console.log("Password is stored as secret");
101
} else {
102
console.log("Password is plain text");
103
}
104
});
105
106
// Use secret in resource
107
const application = new aws.ecs.TaskDefinition("app-task", {
108
containerDefinitions: pulumi.jsonStringify([{
109
name: "app",
110
image: "myapp:latest",
111
environment: [
112
{
113
name: "DB_HOST",
114
value: dbStack.getOutput("endpoint"),
115
},
116
{
117
name: "DB_PASSWORD",
118
value: dbPassword, // Maintains secret status
119
},
120
],
121
}]),
122
});
123
```
124
125
### Conditional Stack References
126
127
```typescript
128
import * as pulumi from "@pulumi/pulumi";
129
130
const config = new pulumi.Config();
131
const environment = config.require("environment");
132
133
// Reference different stacks based on environment
134
const infraStackName = environment === "production"
135
? "myorg/infrastructure/production"
136
: "myorg/infrastructure/staging";
137
138
const infraStack = new pulumi.StackReference("infra", {
139
name: infraStackName,
140
});
141
142
// Get environment-appropriate resources
143
const vpc = infraStack.getOutput("vpcId");
144
const certificateArn = infraStack.getOutput("sslCertificateArn");
145
```
146
147
### Multi-Stack Dependencies
148
149
```typescript
150
import * as pulumi from "@pulumi/pulumi";
151
152
// Reference multiple related stacks
153
const networkStack = new pulumi.StackReference("network", {
154
name: "myorg/network/production",
155
});
156
157
const securityStack = new pulumi.StackReference("security", {
158
name: "myorg/security/production",
159
});
160
161
const monitoringStack = new pulumi.StackReference("monitoring", {
162
name: "myorg/monitoring/production",
163
});
164
165
// Combine outputs from multiple stacks
166
const webService = new aws.ecs.Service("web-service", {
167
cluster: networkStack.getOutput("ecsClusterId"),
168
taskDefinition: taskDefinition.arn,
169
loadBalancers: [{
170
targetGroupArn: networkStack.getOutput("webTargetGroupArn"),
171
containerName: "web",
172
containerPort: 80,
173
}],
174
serviceConnectConfiguration: {
175
enabled: true,
176
namespace: securityStack.getOutput("serviceConnectNamespace"),
177
},
178
});
179
180
// Export combined information
181
export const serviceEndpoint = pulumi.interpolate`https://${networkStack.getOutput("loadBalancerDnsName")}`;
182
export const monitoringDashboard = monitoringStack.getOutput("dashboardUrl");
183
```
184
185
### Error Handling
186
187
```typescript
188
import * as pulumi from "@pulumi/pulumi";
189
190
const remoteStack = new pulumi.StackReference("remote", {
191
name: "external-org/shared-services/production",
192
});
193
194
// Safe access with fallbacks
195
const databaseUrl = remoteStack.getOutput("databaseUrl").apply(url => {
196
if (!url) {
197
throw new Error("Database URL not available from remote stack");
198
}
199
return url;
200
});
201
202
// Optional outputs with defaults
203
const cacheEndpoint = remoteStack.getOutput("cacheEndpoint").apply(endpoint =>
204
endpoint || "localhost:6379"
205
);
206
207
// Validate required outputs exist
208
const requiredOutputs = ["vpcId", "subnetIds", "securityGroupId"];
209
210
requiredOutputs.forEach(outputName => {
211
remoteStack.getOutput(outputName).apply(value => {
212
if (value === undefined || value === null) {
213
throw new Error(`Required output '${outputName}' is missing from remote stack`);
214
}
215
});
216
});
217
```
218
219
### Stack Reference Patterns
220
221
```typescript
222
import * as pulumi from "@pulumi/pulumi";
223
224
// Utility function for consistent stack naming
225
function createStackReference(component: string, environment: string): pulumi.StackReference {
226
const org = pulumi.getOrganization();
227
const stackName = `${org}/${component}/${environment}`;
228
229
return new pulumi.StackReference(`${component}-${environment}`, {
230
name: stackName,
231
});
232
}
233
234
// Use with consistent naming pattern
235
const currentEnv = new pulumi.Config().require("environment");
236
237
const network = createStackReference("network", currentEnv);
238
const security = createStackReference("security", currentEnv);
239
const data = createStackReference("data-platform", currentEnv);
240
241
// Helper for getting typed outputs
242
function getTypedOutput<T>(stackRef: pulumi.StackReference, outputName: string): pulumi.Output<T> {
243
return stackRef.getOutput(outputName) as pulumi.Output<T>;
244
}
245
246
// Usage with type safety
247
interface NetworkOutputs {
248
vpcId: string;
249
privateSubnetIds: string[];
250
publicSubnetIds: string[];
251
}
252
253
const networkOutputs = pulumi.all({
254
vpcId: getTypedOutput<string>(network, "vpcId"),
255
privateSubnetIds: getTypedOutput<string[]>(network, "privateSubnetIds"),
256
publicSubnetIds: getTypedOutput<string[]>(network, "publicSubnetIds"),
257
});
258
```
259
260
## Best Practices
261
262
- Use consistent stack naming conventions across your organization
263
- Handle missing outputs gracefully with appropriate defaults or errors
264
- Be mindful of secret outputs and maintain their secret status
265
- Use stack references to enforce separation of concerns between infrastructure layers
266
- Document the expected outputs from each stack for consumers
267
- Consider using typed interfaces for complex output structures
268
- Test stack references in non-production environments first
269
- Use organization-scoped stack names for shared infrastructure
270
- Plan for stack lifecycle management and migration strategies