Stacks Cloud & Deployment
AWS-focused cloud deployment using CloudFormation via @stacksjs/ts-cloud.
Key Paths
- Cloud package:
storage/framework/core/cloud/src/
- Deploy package:
storage/framework/core/deploy/
- CDK stacks:
storage/framework/cloud/ (deploy.ts, cdk.json, package.json)
- Cloud config:
cloud/ (serverless.ts, servers.ts, deploy-script.ts)
- Cloud driver state:
storage/cloud/ (ts-cloud's stateDir, set in config/cloud.ts)
- Configuration:
config/cloud.ts
Deployment Modes
Server Mode (EC2)
- EC2 instances with configurable types (t3.micro, t4g.nano, etc.)
- Application Load Balancer (ALB)
- VPC with public/private subnets
- Security groups with firewall rules
- Auto-scaling capabilities
- SQLite database on instance
- Docker support via Dockerfile
Serverless Mode (Lambda)
- Lambda functions for API
- API Gateway (REST/WebSocket)
- CloudFront CDN for static assets
- S3 buckets (frontend, docs, logs, assets)
- SQS queues for background jobs
- DynamoDB (optional)
Deployment Flow
buddy deploy # deploy to cloud
- Validates APP_KEY format (colon-separated)
- Checks AWS region and credentials
- Validates app URL, name, team configuration
- Creates
InfrastructureGenerator from cloud config
- Generates CloudFormation template
- Creates or updates stack with:
- Capabilities:
CAPABILITY_IAM, CAPABILITY_NAMED_IAM
- Tags: Environment, Project, ManagedBy
- OnFailure: ROLLBACK
Cloud Helper Functions
import { getSecurityGroupId, purchaseDomain, hasBeenDeployed, isFirstDeployment, isFailedState } from '@stacksjs/cloud'
// Domain management
await purchaseDomain('example.com', { years: 1, privacy: true, autoRenew: true })
// Infrastructure queries
const sgId = await getSecurityGroupId('my-sg')
const jumpBoxId = await getJumpBoxInstanceId('stack-name')
const deployed = await hasBeenDeployed()
const firstDeploy = await isFirstDeployment()
const failed = await isFailedState()
// Resource management
await addJumpBox('stack-name')
await deleteJumpBox('stack-name')
await deleteEc2Instance(instanceId, 'stack-name')
// Cleanup
await deleteStacksBuckets()
await deleteStacksFunctions()
await deleteLogGroups()
await deleteParameterStore()
await deleteVpcs()
await deleteCdkRemnants()
await deleteIamUsers()
await deleteSubnets()
DNS Functions (AWS Route53)
import { createHostedZone, deleteHostedZone, findHostedZone, getNameservers, updateNameservers } from '@stacksjs/cloud'
const zone = await createHostedZone('example.com')
const zoneId = await findHostedZone('example.com')
const ns = await getNameservers('example.com')
const hostedNs = await getHostedZoneNameservers('example.com')
await updateNameservers(hostedNs, 'example.com')
await deleteHostedZoneRecords('example.com')
await writeNameserversToConfig(nameservers)
Server Configuration (cloud/servers.ts)
export default [
{
name: 'app-server-1',
domain: 'stacksjs.com',
region: 'us-east-1',
type: 'app', // 'app' | 'web' | 'cache' | 'worker' | 'search'
instance: 't3.micro',
disk: 20, // GB
os: 'ubuntu-20-lts-x86_64',
bun: '1.1.26',
database: { type: 'sqlite', name: 'stacks' }
},
// ... more servers
]
Deploy Hooks (cloud/deploy-script.ts)
export default {
beforeDeploy({ environment, region }) {
// Pre-deployment: build assets, validate, notify
},
afterDeploy({ environment, region, outputs }) {
// Post-deployment: cache warming, smoke tests, database seeding
console.log('Public IP:', outputs.PublicIp)
console.log('DNS:', outputs.DNS)
}
}
CLI Commands
buddy deploy # deploy application
buddy cloud --diff # show infrastructure changes
buddy cloud --ssh # SSH into cloud
buddy cloud --invalidate-cache # invalidate CDN
buddy cloud:add --jump-box # add jump box instance
buddy cloud:remove --force # destroy cloud resources
buddy cloud:cleanup # clean retained resources
buddy cloud:optimize-cost # remove optional resources
buddy domains:purchase <domain> # purchase domain via Route53
buddy domains:add <domain> # add existing domain
buddy domains:remove <domain> # remove domain
config/cloud.ts
{
project: { name: 'my-app', slug: 'my-app', region: 'us-east-1' },
mode: 'server', // 'server' | 'serverless'
environments: {
production: { domain: 'app.com', region: 'us-east-1' },
staging: { domain: 'staging.app.com' }
},
infrastructure: {
compute: { type: 't3.micro', spot: false },
loadBalancer: { enabled: true, type: 'application' },
ssl: { enabled: true },
dns: { provider: 'route53' },
storage: { buckets: [] },
cdn: { enabled: true },
cache: { enabled: false },
queue: { enabled: false }
}
}
Infrastructure Stack (storage/framework/cloud/)
deploy.ts — Main deployment script (CDK app entry)
cdk.json — CDK configuration with 54 AWS context settings
package.json — Cloud package dependencies
Stack naming: {slugified-app-name}-cloud
Gotchas
- AWS credentials MUST be configured (
buddy configure:aws or env vars)
- Default region is
us-east-1 (from AWS_DEFAULT_REGION env)
- APP_KEY must be colon-separated format (validated during deployment)
- Server mode uses EC2 + ALB; serverless uses Lambda + API Gateway + CloudFront
- Jump boxes are optional — used for SSH access to private instances
cloud:remove with --force skips confirmation — destructive operation
- CDK toolkit stack is named
stacks-toolkit
- Environment mapping:
local → development, others preserved
- Deploy hooks run before/after deployment for custom logic
- The cloud package has its own
package.json with framework dependencies
1---2name: stacks-cloud-33description: Use when deploying or managing cloud infrastructure for Stacks — AWS deployment via CloudFormation/CDK, server mode (EC2, ALB, VPC), serverless mode (Lambda, API Gateway, CloudFront), jump boxes, domain management (Route53), S3 storage, SES email, edge computing, security groups, IAM, or the cloud configuration. Covers @stacksjs/cloud, @stacksjs/deploy, storage/framework/cloud/, and cloud/.4license: MIT5---67# Stacks Cloud & Deployment89AWS-focused cloud deployment using CloudFormation via `@stacksjs/ts-cloud`.1011## Key Paths12- Cloud package: `storage/framework/core/cloud/src/`13- Deploy package: `storage/framework/core/deploy/`14- CDK stacks: `storage/framework/cloud/` (deploy.ts, cdk.json, package.json)15- Cloud config: `cloud/` (serverless.ts, servers.ts, deploy-script.ts)16- Cloud driver state: `storage/cloud/` (ts-cloud's `stateDir`, set in `config/cloud.ts`)17- Configuration: `config/cloud.ts`1819## Deployment Modes2021### Server Mode (EC2)22- EC2 instances with configurable types (t3.micro, t4g.nano, etc.)23- Application Load Balancer (ALB)24- VPC with public/private subnets25- Security groups with firewall rules26- Auto-scaling capabilities27- SQLite database on instance28- Docker support via Dockerfile2930### Serverless Mode (Lambda)31- Lambda functions for API32- API Gateway (REST/WebSocket)33- CloudFront CDN for static assets34- S3 buckets (frontend, docs, logs, assets)35- SQS queues for background jobs36- DynamoDB (optional)3738## Deployment Flow3940```bash41buddy deploy # deploy to cloud42```43441. Validates APP_KEY format (colon-separated)452. Checks AWS region and credentials463. Validates app URL, name, team configuration474. Creates `InfrastructureGenerator` from cloud config485. Generates CloudFormation template496. Creates or updates stack with:50 - Capabilities: `CAPABILITY_IAM`, `CAPABILITY_NAMED_IAM`51 - Tags: Environment, Project, ManagedBy52 - OnFailure: ROLLBACK5354## Cloud Helper Functions5556```typescript57import { getSecurityGroupId, purchaseDomain, hasBeenDeployed, isFirstDeployment, isFailedState } from '@stacksjs/cloud'5859// Domain management60await purchaseDomain('example.com', { years: 1, privacy: true, autoRenew: true })6162// Infrastructure queries63const sgId = await getSecurityGroupId('my-sg')64const jumpBoxId = await getJumpBoxInstanceId('stack-name')65const deployed = await hasBeenDeployed()66const firstDeploy = await isFirstDeployment()67const failed = await isFailedState()6869// Resource management70await addJumpBox('stack-name')71await deleteJumpBox('stack-name')72await deleteEc2Instance(instanceId, 'stack-name')7374// Cleanup75await deleteStacksBuckets()76await deleteStacksFunctions()77await deleteLogGroups()78await deleteParameterStore()79await deleteVpcs()80await deleteCdkRemnants()81await deleteIamUsers()82await deleteSubnets()83```8485## DNS Functions (AWS Route53)8687```typescript88import { createHostedZone, deleteHostedZone, findHostedZone, getNameservers, updateNameservers } from '@stacksjs/cloud'8990const zone = await createHostedZone('example.com')91const zoneId = await findHostedZone('example.com')92const ns = await getNameservers('example.com')93const hostedNs = await getHostedZoneNameservers('example.com')94await updateNameservers(hostedNs, 'example.com')95await deleteHostedZoneRecords('example.com')96await writeNameserversToConfig(nameservers)97```9899## Server Configuration (cloud/servers.ts)100101```typescript102export default [103 {104 name: 'app-server-1',105 domain: 'stacksjs.com',106 region: 'us-east-1',107 type: 'app', // 'app' | 'web' | 'cache' | 'worker' | 'search'108 instance: 't3.micro',109 disk: 20, // GB110 os: 'ubuntu-20-lts-x86_64',111 bun: '1.1.26',112 database: { type: 'sqlite', name: 'stacks' }113 },114 // ... more servers115]116```117118## Deploy Hooks (cloud/deploy-script.ts)119120```typescript121export default {122 beforeDeploy({ environment, region }) {123 // Pre-deployment: build assets, validate, notify124 },125 afterDeploy({ environment, region, outputs }) {126 // Post-deployment: cache warming, smoke tests, database seeding127 console.log('Public IP:', outputs.PublicIp)128 console.log('DNS:', outputs.DNS)129 }130}131```132133## CLI Commands134135```bash136buddy deploy # deploy application137buddy cloud --diff # show infrastructure changes138buddy cloud --ssh # SSH into cloud139buddy cloud --invalidate-cache # invalidate CDN140buddy cloud:add --jump-box # add jump box instance141buddy cloud:remove --force # destroy cloud resources142buddy cloud:cleanup # clean retained resources143buddy cloud:optimize-cost # remove optional resources144buddy domains:purchase <domain> # purchase domain via Route53145buddy domains:add <domain> # add existing domain146buddy domains:remove <domain> # remove domain147```148149## config/cloud.ts150151```typescript152{153 project: { name: 'my-app', slug: 'my-app', region: 'us-east-1' },154 mode: 'server', // 'server' | 'serverless'155 environments: {156 production: { domain: 'app.com', region: 'us-east-1' },157 staging: { domain: 'staging.app.com' }158 },159 infrastructure: {160 compute: { type: 't3.micro', spot: false },161 loadBalancer: { enabled: true, type: 'application' },162 ssl: { enabled: true },163 dns: { provider: 'route53' },164 storage: { buckets: [] },165 cdn: { enabled: true },166 cache: { enabled: false },167 queue: { enabled: false }168 }169}170```171172## Infrastructure Stack (storage/framework/cloud/)173174- `deploy.ts` — Main deployment script (CDK app entry)175- `cdk.json` — CDK configuration with 54 AWS context settings176- `package.json` — Cloud package dependencies177178Stack naming: `{slugified-app-name}-cloud`179180## Gotchas181- AWS credentials MUST be configured (`buddy configure:aws` or env vars)182- Default region is `us-east-1` (from AWS_DEFAULT_REGION env)183- APP_KEY must be colon-separated format (validated during deployment)184- Server mode uses EC2 + ALB; serverless uses Lambda + API Gateway + CloudFront185- Jump boxes are optional — used for SSH access to private instances186- `cloud:remove` with `--force` skips confirmation — destructive operation187- CDK toolkit stack is named `stacks-toolkit`188- Environment mapping: `local` → `development`, others preserved189- Deploy hooks run before/after deployment for custom logic190- The cloud package has its own `package.json` with framework dependencies