stacktape 3.5.7 → 3.6.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.tsconfig.bun-build.json +1 -0
- package/ai-docs/cli-ref/aws-profile-create.md +22 -0
- package/ai-docs/cli-ref/aws-profile-delete.md +22 -0
- package/ai-docs/cli-ref/aws-profile-list.md +20 -0
- package/ai-docs/cli-ref/aws-profile-update.md +22 -0
- package/ai-docs/cli-ref/bastion-session.md +29 -0
- package/ai-docs/cli-ref/bastion-tunnel.md +30 -0
- package/ai-docs/cli-ref/bucket-sync.md +30 -0
- package/ai-docs/cli-ref/cf-module-update.md +26 -0
- package/ai-docs/cli-ref/cf-rollback.md +28 -0
- package/ai-docs/cli-ref/codebuild-deploy.md +34 -0
- package/ai-docs/cli-ref/compile-template.md +25 -0
- package/ai-docs/cli-ref/container-session.md +30 -0
- package/ai-docs/cli-ref/debug-alarms.md +28 -0
- package/ai-docs/cli-ref/debug-aws-sdk.md +33 -0
- package/ai-docs/cli-ref/debug-container-exec.md +36 -0
- package/ai-docs/cli-ref/debug-dynamodb.md +35 -0
- package/ai-docs/cli-ref/debug-logs.md +34 -0
- package/ai-docs/cli-ref/debug-metrics.md +33 -0
- package/ai-docs/cli-ref/debug-opensearch.md +35 -0
- package/ai-docs/cli-ref/debug-redis.md +36 -0
- package/ai-docs/cli-ref/debug-sql.md +35 -0
- package/ai-docs/cli-ref/defaults-configure.md +29 -0
- package/ai-docs/cli-ref/defaults-list.md +20 -0
- package/ai-docs/cli-ref/delete.md +24 -0
- package/ai-docs/cli-ref/deploy.md +25 -0
- package/ai-docs/cli-ref/deployment-script-run.md +28 -0
- package/ai-docs/cli-ref/dev-stop.md +26 -0
- package/ai-docs/cli-ref/dev.md +45 -0
- package/ai-docs/cli-ref/domain-add.md +26 -0
- package/ai-docs/cli-ref/help.md +18 -0
- package/ai-docs/cli-ref/info-operations.md +22 -0
- package/ai-docs/cli-ref/info-stack.md +30 -0
- package/ai-docs/cli-ref/info-stacks.md +26 -0
- package/ai-docs/cli-ref/info-whoami.md +22 -0
- package/ai-docs/cli-ref/init.md +30 -0
- package/ai-docs/cli-ref/login.md +20 -0
- package/ai-docs/cli-ref/logout.md +18 -0
- package/ai-docs/cli-ref/mcp-add.md +22 -0
- package/ai-docs/cli-ref/mcp.md +20 -0
- package/ai-docs/cli-ref/org-create.md +24 -0
- package/ai-docs/cli-ref/org-delete.md +24 -0
- package/ai-docs/cli-ref/org-list.md +22 -0
- package/ai-docs/cli-ref/package-workloads.md +25 -0
- package/ai-docs/cli-ref/param-get.md +26 -0
- package/ai-docs/cli-ref/preview-changes.md +23 -0
- package/ai-docs/cli-ref/project-create.md +22 -0
- package/ai-docs/cli-ref/projects-list.md +22 -0
- package/ai-docs/cli-ref/rollback.md +28 -0
- package/ai-docs/cli-ref/script-run.md +29 -0
- package/ai-docs/cli-ref/secret-create.md +28 -0
- package/ai-docs/cli-ref/secret-delete.md +26 -0
- package/ai-docs/cli-ref/secret-get.md +26 -0
- package/ai-docs/cli-ref/upgrade.md +20 -0
- package/ai-docs/cli-ref/version.md +18 -0
- package/ai-docs/concept/connecting-resources.md +369 -0
- package/ai-docs/concept/directives.md +371 -0
- package/ai-docs/concept/extending-cloudformation.md +315 -0
- package/ai-docs/concept/overrides-and-transforms.md +352 -0
- package/ai-docs/concept/stages-and-environments.md +347 -0
- package/ai-docs/concept/typescript-config.md +447 -0
- package/ai-docs/concept/yaml-config.md +338 -0
- package/ai-docs/config-ref/_root.md +142 -0
- package/ai-docs/config-ref/application-load-balancer.md +1109 -0
- package/ai-docs/config-ref/astro-web.md +115 -0
- package/ai-docs/config-ref/aws-cdk-construct.md +68 -0
- package/ai-docs/config-ref/bastion.md +93 -0
- package/ai-docs/config-ref/batch-job.md +179 -0
- package/ai-docs/config-ref/bucket.md +348 -0
- package/ai-docs/config-ref/cdn.md +496 -0
- package/ai-docs/config-ref/custom-resource.md +80 -0
- package/ai-docs/config-ref/deployment-script.md +79 -0
- package/ai-docs/config-ref/dynamo-db-table.md +202 -0
- package/ai-docs/config-ref/edge-lambda-function.md +87 -0
- package/ai-docs/config-ref/efs-filesystem.md +72 -0
- package/ai-docs/config-ref/event-bus.md +63 -0
- package/ai-docs/config-ref/function.md +409 -0
- package/ai-docs/config-ref/hosting-bucket.md +171 -0
- package/ai-docs/config-ref/http-api-gateway.md +149 -0
- package/ai-docs/config-ref/http-endpoint.md +92 -0
- package/ai-docs/config-ref/kinesis-stream.md +97 -0
- package/ai-docs/config-ref/mongo-db-atlas-cluster.md +254 -0
- package/ai-docs/config-ref/multi-container-workload.md +399 -0
- package/ai-docs/config-ref/network-load-balancer.md +118 -0
- package/ai-docs/config-ref/nextjs-web.md +147 -0
- package/ai-docs/config-ref/nuxt-web.md +81 -0
- package/ai-docs/config-ref/open-search.md +206 -0
- package/ai-docs/config-ref/private-service.md +75 -0
- package/ai-docs/config-ref/redis-cluster.md +223 -0
- package/ai-docs/config-ref/relational-database.md +525 -0
- package/ai-docs/config-ref/remix-web.md +74 -0
- package/ai-docs/config-ref/sns-topic.md +69 -0
- package/ai-docs/config-ref/solidstart-web.md +75 -0
- package/ai-docs/config-ref/sqs-queue-not-empty.md +405 -0
- package/ai-docs/config-ref/sqs-queue.md +232 -0
- package/ai-docs/config-ref/state-machine.md +235 -0
- package/ai-docs/config-ref/sveltekit-web.md +81 -0
- package/ai-docs/config-ref/tanstack-web.md +75 -0
- package/ai-docs/config-ref/upstash-redis.md +59 -0
- package/ai-docs/config-ref/user-auth-pool.md +876 -0
- package/ai-docs/config-ref/web-app-firewall.md +212 -0
- package/ai-docs/config-ref/web-service.md +178 -0
- package/ai-docs/config-ref/worker-service.md +41 -0
- package/ai-docs/getting-started/console.md +232 -0
- package/ai-docs/getting-started/deployment.md +434 -0
- package/ai-docs/getting-started/dev-mode.md +118 -0
- package/ai-docs/getting-started/how-it-works.md +119 -0
- package/ai-docs/getting-started/intro.md +157 -0
- package/ai-docs/getting-started/using-with-ai.md +228 -0
- package/ai-docs/getting-started/workflow.md +197 -0
- package/ai-docs/index.json +1514 -0
- package/ai-docs/recipe/background-jobs.md +183 -0
- package/ai-docs/recipe/database-migrations.md +240 -0
- package/ai-docs/recipe/graphql-api.md +211 -0
- package/ai-docs/recipe/monorepo-setup.md +183 -0
- package/ai-docs/recipe/nextjs-full-stack.md +188 -0
- package/ai-docs/recipe/rest-api-with-database.md +156 -0
- package/ai-docs/recipe/scheduled-tasks.md +186 -0
- package/ai-docs/recipe/static-website.md +241 -0
- package/ai-docs/troubleshooting/cloudformation-stack-states.md +189 -0
- package/bin/stacktape.js +206 -41
- package/package.json +1 -1
- package/plain.d.ts +309 -54
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
---
|
|
2
|
+
docType: concept
|
|
3
|
+
title: Overrides & Transforms
|
|
4
|
+
tags:
|
|
5
|
+
- overrides
|
|
6
|
+
- transforms
|
|
7
|
+
- concept
|
|
8
|
+
source: docs/_curated-docs/concepts/overrides-and-transforms.mdx
|
|
9
|
+
priority: 1
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Overrides & Transforms
|
|
13
|
+
|
|
14
|
+
Stacktape generates CloudFormation templates from your configuration. Sometimes you need to customize the underlying AWS resources beyond what Stacktape exposes. Overrides and transforms give you this power.
|
|
15
|
+
|
|
16
|
+
## Understanding Child Resources
|
|
17
|
+
|
|
18
|
+
Each Stacktape resource creates one or more CloudFormation resources ("child resources"). For example, a `function` creates:
|
|
19
|
+
|
|
20
|
+
- AWS Lambda Function
|
|
21
|
+
- IAM Role
|
|
22
|
+
- CloudWatch Log Group
|
|
23
|
+
- (Optionally) Event Source Mappings, Permissions, etc.
|
|
24
|
+
|
|
25
|
+
You can view the child resources for any Stacktape resource:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
stacktape stack-info --stage dev --region us-east-1 --detailed
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Or use the Stacktape Console's resource inspector.
|
|
32
|
+
|
|
33
|
+
`[IMAGE PLACEHOLDER: console-child-resources-view]`
|
|
34
|
+
|
|
35
|
+
## Overrides
|
|
36
|
+
|
|
37
|
+
Overrides let you set specific properties on child CloudFormation resources.
|
|
38
|
+
|
|
39
|
+
### Basic Override
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
resources:
|
|
43
|
+
handler:
|
|
44
|
+
type: function
|
|
45
|
+
properties:
|
|
46
|
+
packaging:
|
|
47
|
+
type: stacktape-lambda-buildpack
|
|
48
|
+
properties:
|
|
49
|
+
entryfilePath: ./src/handler.ts
|
|
50
|
+
overrides:
|
|
51
|
+
# Override the Lambda function's description
|
|
52
|
+
StpLambdaFunction:
|
|
53
|
+
Description: 'My custom description'
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Finding Child Resource Names
|
|
57
|
+
|
|
58
|
+
To override a property, you need to know the logical name of the child resource. Use:
|
|
59
|
+
|
|
60
|
+
1. **CLI**: `stacktape stack-info --detailed`
|
|
61
|
+
2. **Console**: View resource details
|
|
62
|
+
3. **Compile template**: `stacktape compile-template` and inspect the output
|
|
63
|
+
|
|
64
|
+
Common child resource names:
|
|
65
|
+
|
|
66
|
+
| Stacktape Resource | Child Resources |
|
|
67
|
+
| --------------------- | ------------------------------------------------------------------------- |
|
|
68
|
+
| `function` | `StpLambdaFunction`, `StpLambdaFunctionRole`, `StpLambdaFunctionLogGroup` |
|
|
69
|
+
| `web-service` | `StpEcsService`, `StpEcsTaskDefinition`, `StpEcsTaskRole` |
|
|
70
|
+
| `relational-database` | `StpRdsInstance`, `StpRdsSecurityGroup`, `StpRdsSubnetGroup` |
|
|
71
|
+
| `bucket` | `StpS3Bucket` |
|
|
72
|
+
| `http-api-gateway` | `StpHttpApi` |
|
|
73
|
+
|
|
74
|
+
### Override Example: Lambda Reserved Concurrency
|
|
75
|
+
|
|
76
|
+
```yaml
|
|
77
|
+
resources:
|
|
78
|
+
handler:
|
|
79
|
+
type: function
|
|
80
|
+
properties:
|
|
81
|
+
packaging:
|
|
82
|
+
type: stacktape-lambda-buildpack
|
|
83
|
+
properties:
|
|
84
|
+
entryfilePath: ./src/handler.ts
|
|
85
|
+
overrides:
|
|
86
|
+
StpLambdaFunction:
|
|
87
|
+
ReservedConcurrentExecutions: 100
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Override Example: S3 Bucket Policy
|
|
91
|
+
|
|
92
|
+
```yaml
|
|
93
|
+
resources:
|
|
94
|
+
uploads:
|
|
95
|
+
type: bucket
|
|
96
|
+
properties:
|
|
97
|
+
overrides:
|
|
98
|
+
StpS3Bucket:
|
|
99
|
+
PublicAccessBlockConfiguration:
|
|
100
|
+
BlockPublicAcls: true
|
|
101
|
+
BlockPublicPolicy: true
|
|
102
|
+
IgnorePublicAcls: true
|
|
103
|
+
RestrictPublicBuckets: true
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Override Example: RDS Parameter Group
|
|
107
|
+
|
|
108
|
+
```yaml
|
|
109
|
+
resources:
|
|
110
|
+
database:
|
|
111
|
+
type: relational-database
|
|
112
|
+
properties:
|
|
113
|
+
engine:
|
|
114
|
+
type: postgres
|
|
115
|
+
properties:
|
|
116
|
+
version: '16'
|
|
117
|
+
overrides:
|
|
118
|
+
StpRdsParameterGroup:
|
|
119
|
+
Parameters:
|
|
120
|
+
max_connections: '200'
|
|
121
|
+
shared_buffers: '256MB'
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Transforms
|
|
125
|
+
|
|
126
|
+
Transforms are functions that modify the CloudFormation properties. They're more powerful than overrides because you can compute values based on existing properties.
|
|
127
|
+
|
|
128
|
+
### Basic Transform
|
|
129
|
+
|
|
130
|
+
```yaml
|
|
131
|
+
resources:
|
|
132
|
+
handler:
|
|
133
|
+
type: function
|
|
134
|
+
properties:
|
|
135
|
+
packaging:
|
|
136
|
+
type: stacktape-lambda-buildpack
|
|
137
|
+
properties:
|
|
138
|
+
entryfilePath: ./src/handler.ts
|
|
139
|
+
memory: 128
|
|
140
|
+
transforms:
|
|
141
|
+
StpLambdaFunction: |
|
|
142
|
+
(props) => ({
|
|
143
|
+
...props,
|
|
144
|
+
MemorySize: props.MemorySize * 2 // Double the memory
|
|
145
|
+
})
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### TypeScript Transforms
|
|
149
|
+
|
|
150
|
+
In TypeScript configuration, transforms are cleaner:
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { defineConfig, LambdaFunction, StacktapeLambdaBuildpackPackaging } from 'stacktape';
|
|
154
|
+
|
|
155
|
+
export default defineConfig(() => {
|
|
156
|
+
const handler = new LambdaFunction({
|
|
157
|
+
packaging: new StacktapeLambdaBuildpackPackaging({
|
|
158
|
+
entryfilePath: './src/handler.ts'
|
|
159
|
+
}),
|
|
160
|
+
memory: 128,
|
|
161
|
+
transforms: {
|
|
162
|
+
StpLambdaFunction: (props) => ({
|
|
163
|
+
...props,
|
|
164
|
+
MemorySize: (props.MemorySize ?? 128) * 2,
|
|
165
|
+
Description: `Handler with ${props.MemorySize}MB memory`
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return { resources: { handler } };
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Transform Example: Add Lambda Layers
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
const handler = new LambdaFunction({
|
|
178
|
+
packaging: new StacktapeLambdaBuildpackPackaging({
|
|
179
|
+
entryfilePath: './src/handler.ts'
|
|
180
|
+
}),
|
|
181
|
+
transforms: {
|
|
182
|
+
StpLambdaFunction: (props) => ({
|
|
183
|
+
...props,
|
|
184
|
+
Layers: [...(props.Layers || []), 'arn:aws:lambda:us-east-1:123456789:layer:my-layer:1']
|
|
185
|
+
})
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Transform Example: Custom ECS Task Definition
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
const api = new WebService({
|
|
194
|
+
packaging: new StacktapeImageBuildpackPackaging({
|
|
195
|
+
entryfilePath: './src/server.ts'
|
|
196
|
+
}),
|
|
197
|
+
transforms: {
|
|
198
|
+
StpEcsTaskDefinition: (props) => ({
|
|
199
|
+
...props,
|
|
200
|
+
ContainerDefinitions: props.ContainerDefinitions.map((container) => ({
|
|
201
|
+
...container,
|
|
202
|
+
Ulimits: [{ Name: 'nofile', SoftLimit: 65536, HardLimit: 65536 }]
|
|
203
|
+
}))
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Overrides vs Transforms
|
|
210
|
+
|
|
211
|
+
| Feature | Overrides | Transforms |
|
|
212
|
+
| -------------- | ----------------------- | ------------------------ |
|
|
213
|
+
| Syntax | Static values | JavaScript function |
|
|
214
|
+
| Use case | Set specific properties | Compute or modify values |
|
|
215
|
+
| Complexity | Simple | More powerful |
|
|
216
|
+
| Merge behavior | Shallow merge | Full control |
|
|
217
|
+
|
|
218
|
+
Use **overrides** when you know the exact value you want to set.
|
|
219
|
+
Use **transforms** when you need to compute values or modify existing properties.
|
|
220
|
+
|
|
221
|
+
## Viewing Generated CloudFormation
|
|
222
|
+
|
|
223
|
+
To see the final CloudFormation template after overrides and transforms:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
stacktape compile-template --stage dev --region us-east-1
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
This outputs `compiled-template.yaml` which you can inspect.
|
|
230
|
+
|
|
231
|
+
## Adding Raw CloudFormation Resources
|
|
232
|
+
|
|
233
|
+
For resources Stacktape doesn't support, add raw CloudFormation:
|
|
234
|
+
|
|
235
|
+
```yaml
|
|
236
|
+
resources:
|
|
237
|
+
handler:
|
|
238
|
+
type: function
|
|
239
|
+
properties:
|
|
240
|
+
packaging:
|
|
241
|
+
type: stacktape-lambda-buildpack
|
|
242
|
+
properties:
|
|
243
|
+
entryfilePath: ./src/handler.ts
|
|
244
|
+
|
|
245
|
+
cloudformationResources:
|
|
246
|
+
# Add a custom SNS topic
|
|
247
|
+
MyCustomTopic:
|
|
248
|
+
Type: AWS::SNS::Topic
|
|
249
|
+
Properties:
|
|
250
|
+
TopicName: my-custom-topic
|
|
251
|
+
DisplayName: My Custom Topic
|
|
252
|
+
|
|
253
|
+
# Subscribe the function to the topic
|
|
254
|
+
MyTopicSubscription:
|
|
255
|
+
Type: AWS::SNS::Subscription
|
|
256
|
+
Properties:
|
|
257
|
+
Protocol: lambda
|
|
258
|
+
TopicArn: !Ref MyCustomTopic
|
|
259
|
+
Endpoint: !GetAtt StpHandlerStpLambdaFunction.Arn
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Reference CloudFormation resources in Stacktape:
|
|
263
|
+
|
|
264
|
+
```yaml
|
|
265
|
+
resources:
|
|
266
|
+
handler:
|
|
267
|
+
type: function
|
|
268
|
+
properties:
|
|
269
|
+
environment:
|
|
270
|
+
- name: TOPIC_ARN
|
|
271
|
+
value: $CfResourceParam('MyCustomTopic', 'Arn')
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## AWS CDK Constructs
|
|
275
|
+
|
|
276
|
+
For complex extensions, use AWS CDK constructs:
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
// cdk/monitoring.ts
|
|
280
|
+
import { Construct } from 'constructs';
|
|
281
|
+
import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch';
|
|
282
|
+
|
|
283
|
+
export class MonitoringDashboard extends Construct {
|
|
284
|
+
constructor(scope: Construct, id: string) {
|
|
285
|
+
super(scope, id);
|
|
286
|
+
|
|
287
|
+
new cloudwatch.Dashboard(this, 'Dashboard', {
|
|
288
|
+
dashboardName: 'my-app-dashboard',
|
|
289
|
+
widgets: [
|
|
290
|
+
// Dashboard configuration
|
|
291
|
+
]
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Reference in config:
|
|
298
|
+
|
|
299
|
+
```yaml
|
|
300
|
+
resources:
|
|
301
|
+
handler:
|
|
302
|
+
type: function
|
|
303
|
+
|
|
304
|
+
cdkConstructs:
|
|
305
|
+
- constructPath: ./cdk/monitoring.ts
|
|
306
|
+
constructName: MonitoringDashboard
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
See [Extending with CDK](/extending/cdk-constructs) for more details.
|
|
310
|
+
|
|
311
|
+
## Best Practices
|
|
312
|
+
|
|
313
|
+
1. **Try Stacktape properties first**: Many customizations are available through standard properties
|
|
314
|
+
2. **Use overrides for simple changes**: Static values that don't depend on other properties
|
|
315
|
+
3. **Use transforms for computed values**: When you need to modify or compute based on existing values
|
|
316
|
+
4. **Document your overrides**: Explain why you needed to override
|
|
317
|
+
5. **Test thoroughly**: Overrides bypass Stacktape's validation
|
|
318
|
+
6. **Keep it minimal**: The more you override, the more you need to maintain
|
|
319
|
+
|
|
320
|
+
## Common Override Scenarios
|
|
321
|
+
|
|
322
|
+
### Custom Lambda Runtime
|
|
323
|
+
|
|
324
|
+
```yaml
|
|
325
|
+
overrides:
|
|
326
|
+
StpLambdaFunction:
|
|
327
|
+
Runtime: provided.al2023
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### ECS Health Check
|
|
331
|
+
|
|
332
|
+
```yaml
|
|
333
|
+
overrides:
|
|
334
|
+
StpEcsTaskDefinition:
|
|
335
|
+
ContainerDefinitions:
|
|
336
|
+
- HealthCheck:
|
|
337
|
+
Command: ['CMD-SHELL', 'curl -f http://localhost:3000/health || exit 1']
|
|
338
|
+
Interval: 30
|
|
339
|
+
Timeout: 5
|
|
340
|
+
Retries: 3
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### RDS Enhanced Monitoring
|
|
344
|
+
|
|
345
|
+
```yaml
|
|
346
|
+
overrides:
|
|
347
|
+
StpRdsInstance:
|
|
348
|
+
MonitoringInterval: 60
|
|
349
|
+
MonitoringRoleArn: arn:aws:iam::123456789:role/rds-monitoring-role
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Next Steps
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
---
|
|
2
|
+
docType: concept
|
|
3
|
+
title: Stages & Environments
|
|
4
|
+
tags:
|
|
5
|
+
- stages
|
|
6
|
+
- environments
|
|
7
|
+
- concept
|
|
8
|
+
source: docs/_curated-docs/concepts/stages-and-environments.mdx
|
|
9
|
+
priority: 1
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Stages & Environments
|
|
13
|
+
|
|
14
|
+
Stages allow you to deploy multiple isolated environments from the same codebase. Each stage creates a completely separate set of AWS resources.
|
|
15
|
+
|
|
16
|
+
## What is a Stage?
|
|
17
|
+
|
|
18
|
+
A **stage** is an environment identifier like `dev`, `staging`, or `production`. When you deploy with different stages, Stacktape creates completely separate resources:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Development environment
|
|
22
|
+
stacktape deploy --stage dev --region us-east-1
|
|
23
|
+
# Creates: my-app-dev stack with its own database, functions, etc.
|
|
24
|
+
|
|
25
|
+
# Production environment
|
|
26
|
+
stacktape deploy --stage production --region us-east-1
|
|
27
|
+
# Creates: my-app-production stack with completely separate resources
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Stack Naming
|
|
31
|
+
|
|
32
|
+
Your stack name is derived from your project name and stage:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
{projectName}-{stage}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
For example:
|
|
39
|
+
|
|
40
|
+
- Project: `my-api`, Stage: `dev` → Stack: `my-api-dev`
|
|
41
|
+
- Project: `my-api`, Stage: `production` → Stack: `my-api-production`
|
|
42
|
+
|
|
43
|
+
## Stage-Based Configuration
|
|
44
|
+
|
|
45
|
+
### TypeScript (Recommended)
|
|
46
|
+
|
|
47
|
+
Use the `stage` parameter in `defineConfig`:
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { defineConfig, RelationalDatabase, LambdaFunction, RdsEnginePostgres, $Secret } from 'stacktape';
|
|
51
|
+
|
|
52
|
+
export default defineConfig(({ stage }) => {
|
|
53
|
+
const isProduction = stage === 'production';
|
|
54
|
+
|
|
55
|
+
const database = new RelationalDatabase({
|
|
56
|
+
engine: new RdsEnginePostgres({
|
|
57
|
+
version: '16',
|
|
58
|
+
primaryInstance: {
|
|
59
|
+
// Larger instance for production
|
|
60
|
+
instanceSize: isProduction ? 'db.t4g.medium' : 'db.t4g.micro',
|
|
61
|
+
// Multi-AZ only in production
|
|
62
|
+
multiAz: isProduction
|
|
63
|
+
}
|
|
64
|
+
}),
|
|
65
|
+
credentials: {
|
|
66
|
+
masterUserPassword: $Secret(`db-password-${stage}`)
|
|
67
|
+
},
|
|
68
|
+
// Different backup retention
|
|
69
|
+
automatedBackupRetentionDays: isProduction ? 7 : 1
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const handler = new LambdaFunction({
|
|
73
|
+
// More memory for production
|
|
74
|
+
memory: isProduction ? 1024 : 256,
|
|
75
|
+
// Longer timeout for production
|
|
76
|
+
timeout: isProduction ? 30 : 10,
|
|
77
|
+
environment: {
|
|
78
|
+
NODE_ENV: isProduction ? 'production' : 'development',
|
|
79
|
+
LOG_LEVEL: isProduction ? 'warn' : 'debug'
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return { resources: { database, handler } };
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### YAML with Directives
|
|
88
|
+
|
|
89
|
+
In YAML, use variables and the `$Stage()` directive:
|
|
90
|
+
|
|
91
|
+
```yaml
|
|
92
|
+
variables:
|
|
93
|
+
instanceSize:
|
|
94
|
+
$CfIf:
|
|
95
|
+
- $CfEquals: [$Stage(), 'production']
|
|
96
|
+
- db.t4g.medium
|
|
97
|
+
- db.t4g.micro
|
|
98
|
+
|
|
99
|
+
resources:
|
|
100
|
+
database:
|
|
101
|
+
type: relational-database
|
|
102
|
+
properties:
|
|
103
|
+
engine:
|
|
104
|
+
type: postgres
|
|
105
|
+
properties:
|
|
106
|
+
primaryInstance:
|
|
107
|
+
instanceSize: $Var('instanceSize')
|
|
108
|
+
credentials:
|
|
109
|
+
masterUserPassword: $Secret($Format('db-password-{}', $Stage()))
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Common Stage Patterns
|
|
113
|
+
|
|
114
|
+
### Development → Staging → Production
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
export default defineConfig(({ stage }) => {
|
|
118
|
+
const config =
|
|
119
|
+
{
|
|
120
|
+
dev: {
|
|
121
|
+
instanceSize: 'db.t4g.micro',
|
|
122
|
+
minInstances: 1,
|
|
123
|
+
maxInstances: 1,
|
|
124
|
+
multiAz: false
|
|
125
|
+
},
|
|
126
|
+
staging: {
|
|
127
|
+
instanceSize: 'db.t4g.small',
|
|
128
|
+
minInstances: 1,
|
|
129
|
+
maxInstances: 3,
|
|
130
|
+
multiAz: false
|
|
131
|
+
},
|
|
132
|
+
production: {
|
|
133
|
+
instanceSize: 'db.t4g.medium',
|
|
134
|
+
minInstances: 2,
|
|
135
|
+
maxInstances: 10,
|
|
136
|
+
multiAz: true
|
|
137
|
+
}
|
|
138
|
+
}[stage] || config.dev; // Default to dev for unknown stages
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
resources: {
|
|
142
|
+
database: new RelationalDatabase({
|
|
143
|
+
engine: new RdsEnginePostgres({
|
|
144
|
+
version: '16',
|
|
145
|
+
primaryInstance: {
|
|
146
|
+
instanceSize: config.instanceSize,
|
|
147
|
+
multiAz: config.multiAz
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
}),
|
|
151
|
+
api: new WebService({
|
|
152
|
+
scaling: {
|
|
153
|
+
minInstances: config.minInstances,
|
|
154
|
+
maxInstances: config.maxInstances
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Feature Branch Stages
|
|
163
|
+
|
|
164
|
+
Create temporary environments for feature branches:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# Deploy feature branch
|
|
168
|
+
stacktape deploy --stage feature-123 --region us-east-1
|
|
169
|
+
|
|
170
|
+
# Test the feature
|
|
171
|
+
curl https://feature-123.api.example.com
|
|
172
|
+
|
|
173
|
+
# Delete when done
|
|
174
|
+
stacktape delete --stage feature-123 --region us-east-1
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Preview Environments
|
|
178
|
+
|
|
179
|
+
The Stacktape Console can automatically create preview environments for pull requests:
|
|
180
|
+
|
|
181
|
+
1. Open a PR
|
|
182
|
+
2. Stacktape automatically deploys a `preview-{pr-number}` stage
|
|
183
|
+
3. PR gets a comment with the deployment URL
|
|
184
|
+
4. When PR is merged/closed, the environment is deleted
|
|
185
|
+
|
|
186
|
+
`[IMAGE PLACEHOLDER: console-preview-environments]`
|
|
187
|
+
|
|
188
|
+
## Stage-Specific Secrets
|
|
189
|
+
|
|
190
|
+
Create separate secrets for each stage:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# Development secrets
|
|
194
|
+
stacktape secret:create --region us-east-1
|
|
195
|
+
# name: db-password-dev
|
|
196
|
+
# value: dev-password
|
|
197
|
+
|
|
198
|
+
# Production secrets
|
|
199
|
+
stacktape secret:create --region us-east-1
|
|
200
|
+
# name: db-password-production
|
|
201
|
+
# value: super-secure-production-password
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Reference in config:
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
export default defineConfig(({ stage }) => {
|
|
208
|
+
const database = new RelationalDatabase({
|
|
209
|
+
credentials: {
|
|
210
|
+
masterUserPassword: $Secret(`db-password-${stage}`)
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
return { resources: { database } };
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Stage-Specific Domains
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
export default defineConfig(({ stage }) => {
|
|
222
|
+
const api = new HttpApiGateway({
|
|
223
|
+
customDomains:
|
|
224
|
+
stage === 'production' ? [{ domainName: 'api.example.com' }] : [{ domainName: `${stage}.api.example.com` }]
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
return { resources: { api } };
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Results:
|
|
232
|
+
|
|
233
|
+
- `production` → `api.example.com`
|
|
234
|
+
- `staging` → `staging.api.example.com`
|
|
235
|
+
- `dev` → `dev.api.example.com`
|
|
236
|
+
|
|
237
|
+
## Conditional Resources
|
|
238
|
+
|
|
239
|
+
Only create certain resources in specific stages:
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
export default defineConfig(({ stage }) => {
|
|
243
|
+
const resources: Record<string, any> = {};
|
|
244
|
+
|
|
245
|
+
// Always create API
|
|
246
|
+
resources.api = new HttpApiGateway({});
|
|
247
|
+
|
|
248
|
+
// Database only in non-ephemeral stages
|
|
249
|
+
if (!stage.startsWith('preview-')) {
|
|
250
|
+
resources.database = new RelationalDatabase({
|
|
251
|
+
engine: new RdsEnginePostgres({ version: '16' })
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Monitoring only in production
|
|
256
|
+
if (stage === 'production') {
|
|
257
|
+
resources.firewall = new WebAppFirewall({ scope: 'regional' });
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return { resources };
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Sharing Resources Across Stages
|
|
265
|
+
|
|
266
|
+
Sometimes you want to share certain resources (like a database) across stages. Use a separate "shared infrastructure" stack:
|
|
267
|
+
|
|
268
|
+
**shared-infra/stacktape.ts:**
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
export default defineConfig(() => {
|
|
272
|
+
const database = new RelationalDatabase({
|
|
273
|
+
engine: new RdsEnginePostgres({ version: '16' })
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
return { resources: { database } };
|
|
277
|
+
});
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**api/stacktape.ts:**
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
export default defineConfig(({ stage }) => {
|
|
284
|
+
const handler = new LambdaFunction({
|
|
285
|
+
environment: {
|
|
286
|
+
DATABASE_URL: $StackOutput(`shared-infra-${stage}`, 'database', 'connectionString')
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
return { resources: { handler } };
|
|
291
|
+
});
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Default Stage and Region
|
|
295
|
+
|
|
296
|
+
Set defaults to avoid typing them every time:
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
stacktape defaults:configure
|
|
300
|
+
# Set default stage: dev
|
|
301
|
+
# Set default region: us-east-1
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Now you can deploy without specifying stage/region:
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
stacktape deploy
|
|
308
|
+
# Uses stage=dev, region=us-east-1
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Override when needed:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
stacktape deploy --stage production --region eu-west-1
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Listing Stages
|
|
318
|
+
|
|
319
|
+
View all deployed stacks:
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
stacktape stack:list --region us-east-1
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Output:
|
|
326
|
+
|
|
327
|
+
```
|
|
328
|
+
┌──────────────────────┬─────────────┬─────────────────────────┐
|
|
329
|
+
│ Stack Name │ Status │ Last Updated │
|
|
330
|
+
├──────────────────────┼─────────────┼─────────────────────────┤
|
|
331
|
+
│ my-api-dev │ DEPLOYED │ 2024-01-15 10:30:00 │
|
|
332
|
+
│ my-api-staging │ DEPLOYED │ 2024-01-14 15:45:00 │
|
|
333
|
+
│ my-api-production │ DEPLOYED │ 2024-01-10 09:00:00 │
|
|
334
|
+
│ my-api-feature-123 │ DEPLOYED │ 2024-01-15 11:00:00 │
|
|
335
|
+
└──────────────────────┴─────────────┴─────────────────────────┘
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## Best Practices
|
|
339
|
+
|
|
340
|
+
1. **Use consistent naming**: `dev`, `staging`, `production` or `development`, `test`, `prod`
|
|
341
|
+
2. **Separate secrets per stage**: Never share production secrets with development
|
|
342
|
+
3. **Start small in dev**: Use minimal resources in development to save costs
|
|
343
|
+
4. **Test in staging**: Make staging as close to production as possible
|
|
344
|
+
5. **Protect production**: Add additional safeguards (WAF, monitoring, multi-AZ)
|
|
345
|
+
6. **Clean up feature stages**: Delete temporary stages when no longer needed
|
|
346
|
+
|
|
347
|
+
## Next Steps
|