Infra iac sst
Skill agents-inc/skills/dist/plugins/infra-iac-sst/skills/infra-iac-sst
The official skills marketplace for Agents Inc, an agent composition framework that builds stacks and compiles specialized subagents for Claude Code
npx -y skills add agents-inc/skills --skill infra-iac-sstAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 18 stars18 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
SST (Ion) infrastructure-as-code — TypeScript-first serverless on AWS with Pulumi, resource linking, and live Lambda dev
SKILL.md
17.2 KB, ~4.1k tokens by cl100k_base, as published. Nobody here has run it
SST (Ion) Patterns
Quick Guide: SST v3 (Ion) is TypeScript-first infrastructure-as-code for AWS, powered by Pulumi/Terraform (not CDK/CloudFormation). Define your entire app in
sst.config.tsusing high-level components (sst.aws.Function,sst.aws.ApiGatewayV2,sst.aws.Bucket,sst.aws.Dynamo, etc.). Use resource linking (link: [bucket]+Resource.MyBucket.name) for type-safe, permission-aware access between components. Usesst devfor live Lambda development with sub-10ms reloads. Use$app.stagefor multi-environment isolation. Usetransformto customize underlying Pulumi resources.
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST use resource linking (link + Resource.*) to connect components — NEVER hardcode ARNs, table names, or bucket names)
(You MUST use $app.stage for environment isolation — NEVER share resources across stages without explicit intent)
(You MUST use sst dev for local development — it provides live Lambda proxying with sub-10ms reloads against real AWS resources)
(You MUST use sst secret set for secrets — NEVER put secrets in sst.config.ts, .env files committed to git, or environment variables)
(You MUST use transform to customize underlying resources — NEVER reach for raw Pulumi resources when an SST component exists)
</critical_requirements>
Examples
- Core Patterns — sst.config.ts structure, Function, resource linking, $app globals, secrets, multi-stage
- API & Data — ApiGatewayV2, Dynamo, Bucket, Queue, Topic, Cron, authorization
- Deployment & DevOps — sst deploy, CI/CD, removal policies, transforms, Vpc, Cluster, frontend frameworks
- Quick Reference — CLI commands, component cheat sheet, global helpers, named constants
Auto-detection: SST, sst.config.ts, sst.aws.Function, sst.aws.ApiGatewayV2, sst.aws.Bucket, sst.aws.Dynamo, sst.aws.Queue, sst.aws.Topic, sst.aws.Cron, sst.aws.Nextjs, sst.aws.Remix, sst.aws.Astro, sst.aws.StaticSite, sst.aws.Vpc, sst.aws.Cluster, sst.aws.Postgres, sst.aws.Router, sst.Linkable, Resource from sst, sst dev, sst deploy, sst remove, sst secret, $app.stage, $transform, $concat, $interpolate, resource linking, live Lambda, Ion
When to use:
- Defining AWS infrastructure in TypeScript with high-level components
- Deploying serverless applications (Lambda, API Gateway, DynamoDB, S3, SQS, SNS)
- Deploying full-stack apps (Next.js, Remix, Astro, SvelteKit, SolidStart on AWS)
- Setting up live Lambda development with real AWS resources
- Managing multi-stage environments (dev, staging, production)
- Connecting infrastructure components with type-safe resource linking
When NOT to use:
- Multi-cloud infrastructure spanning many providers (SST is AWS-focused with limited Cloudflare support)
- Existing Terraform/Pulumi codebases where SST abstraction adds no value
- Projects that need container-only deployments without serverless components
Key patterns covered:
sst.config.tsstructure (app()+run()functions)- Resource linking:
linkproperty +Resource.*SDK - Live Lambda development with
sst dev - AWS components: Function, ApiGatewayV2, Dynamo, Bucket, Queue, Topic, Cron
- Frontend deployments: Nextjs, Remix, Astro, StaticSite
- Multi-stage isolation with
$app.stage - Transforms for customizing underlying Pulumi resources
- Secrets management with
sst secret - Custom linkables with
sst.LinkableandLinkable.wrap - Global helpers:
$app,$dev,$concat,$interpolate,$resolve,$transform
<philosophy>
Philosophy
SST v3 (Ion) replaces CDK/CloudFormation with Pulumi/Terraform for dramatically faster deployments and a simpler programming model. The core ideas:
- One config file — Your entire app is defined in
sst.config.ts. Infrastructure, frontends, and functions all declared together in TypeScript with loops, conditionals, and functions. - Components over constructs — High-level
sst.aws.*components encapsulate best practices (IAM, logging, monitoring). Usetransformto reach into underlying resources when defaults aren't enough. - Resource linking — The killer feature.
link: [bucket]automatically grants IAM permissions and injects type-safe references. Access viaResource.MyBucket.nameat runtime. No manual ARN passing or environment variable wiring. - Stage-based isolation — Every developer gets their own stage (
sst devcreates a personal stack).$app.stagedrives resource naming. Production usessst deploy --stage production. - Live dev against real AWS —
sst devreplaces Lambda functions with stubs that proxy to your local machine. Changes reload in under 10ms. No local emulation — your code runs against real DynamoDB, S3, SQS.
When to use SST:
- Serverless-first applications on AWS (Lambda, API Gateway, DynamoDB, S3, SQS, SNS)
- Full-stack apps deploying frontend frameworks (Next.js, Remix, Astro) to AWS
- Teams that want TypeScript infrastructure with minimal AWS boilerplate
- Projects needing fast local development loops against real cloud resources
When NOT to use SST:
- Multi-cloud infrastructure beyond AWS + Cloudflare (SST's multi-cloud support is limited)
- Container-only workloads with no serverless components (use raw Pulumi or Terraform)
- Existing large Terraform/Pulumi codebases where SST abstraction adds migration cost
<patterns>
Core Patterns
Pattern 1: sst.config.ts Structure
Every SST app has a single sst.config.ts with two functions: app() for metadata and run() for resources.
/// <reference path="./.sst/platform/config.d.ts" />
export default $config({
app(input) {
return {
name: "my-app",
home: "aws",
removal: input.stage === "production" ? "retain" : "remove",
protect: input.stage === "production",
providers: {
aws: { region: "us-east-1" },
},
};
},
async run() {
const bucket = new sst.aws.Bucket("Uploads");
const api = new sst.aws.Function("Api", {
handler: "src/api.handler",
link: [bucket],
});
return { apiUrl: api.url };
},
});
Why good: app() handles metadata and stage-specific policies, run() defines all resources, removal: "retain" protects production data, returned values become outputs in .sst/outputs.json
See examples/core.md for full config with multi-stage, providers, and protect patterns.
Pattern 2: Resource Linking
The defining SST feature. Link resources to grant permissions and type-safe access automatically.
// In sst.config.ts
const table = new sst.aws.Dynamo("Notes", {
fields: { userId: "string", noteId: "string" },
primaryIndex: { hashKey: "userId", rangeKey: "noteId" },
});
new sst.aws.Function("Api", {
handler: "src/api.handler",
link: [table],
});
// In src/api.ts — runtime code
import { Resource } from "sst";
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
const client = new DynamoDBClient({});
// Resource.Notes.name is the table name — type-safe, auto-generated
console.log(Resource.Notes.name);
Why good: No manual ARN passing, IAM permissions granted automatically, type-safe access via generated sst-env.d.ts, works across Functions, frontends, and containers
See examples/core.md for linking patterns including custom linkables.
Pattern 3: Live Lambda Development
sst dev proxies Lambda invocations to your local machine for sub-10ms reload cycles.
# Start live dev — deploys infra, proxies Lambda to local machine
sst dev
# Opens multiplexer: deploys resources, starts frontends, tunnels VPC
// Detect dev mode in handler code
const isLocal = process.env.SST_DEV === "true";
Key behavior: Functions are replaced with stubs that forward events via AppSync to your local machine. Your local code runs as Node.js Workers. Changes reload instantly — no redeploy needed.
Gotcha: Killing sst dev leaves stubs deployed. Subsequent Lambda invocations will timeout until you run sst dev again or sst deploy to replace stubs with real code.
See examples/core.md for dev workflow and debugging setup.
Pattern 4: AWS Components
SST provides high-level components for common AWS services. Each handles IAM, logging, and configuration automatically.
| Component | AWS Service | Use Case |
|---|---|---|
sst.aws.Function | Lambda | Serverless functions |
sst.aws.ApiGatewayV2 | API Gateway v2 | HTTP APIs with routes |
sst.aws.Dynamo | DynamoDB | NoSQL database |
sst.aws.Bucket | S3 | Object storage |
sst.aws.Queue | SQS | Message queues |
sst.aws.Topic | SNS | Pub/sub messaging |
sst.aws.Cron | EventBridge | Scheduled tasks |
sst.aws.Vpc | VPC | Network isolation |
sst.aws.Cluster | ECS | Container workloads |
sst.aws.Postgres | RDS Postgres | Relational database |
sst.aws.Nextjs | Lambda + CloudFront | Next.js deployment |
sst.aws.Remix | Lambda + CloudFront | Remix deployment |
sst.aws.Astro | Lambda + CloudFront | Astro deployment |
sst.aws.StaticSite | S3 + CloudFront | Static site hosting |
sst.aws.Router | CloudFront | URL routing |
See examples/api-data.md for API, database, storage, queue, and cron patterns.
Pattern 5: Secrets Management
Secrets are encrypted and stored in S3, injected into function bundles at deploy time.
# Set a secret (prompts for value)
sst secret set DATABASE_URL
# Set a secret with value inline
sst secret set STRIPE_KEY sk_live_xxx
# Load secrets from a file
sst secret load .env.production
# List all secrets
sst secret list
// Access secrets via resource linking
import { Resource } from "sst";
const stripeKey = Resource.StripeKey.value;
Gotcha: Secrets are per-stage. Set them for each stage separately. Use --fallback to set a default across all stages.
See examples/core.md for secrets with Linkable pattern.
Pattern 6: Transforms
Customize underlying Pulumi resources when SST defaults aren't enough.
// Per-component transform
new sst.aws.Function("Api", {
handler: "src/api.handler",
transform: {
function: (args) => {
args.tracingConfig = { mode: "Active" };
},
},
});
// Global transform — applies to ALL components of a type
$transform(sst.aws.Function, (args) => {
args.environment ??= {};
args.environment.variables ??= {};
args.environment.variables.STAGE = $app.stage;
});
Why good: Transforms let you customize any underlying resource property without abandoning SST's abstractions. Global transforms set defaults across all components.
See examples/deployment.md for transform patterns.
Pattern 7: Multi-Stage Environments
Every stage is a fully isolated deployment. Use $app.stage for conditional configuration.
async run() {
const isProd = $app.stage === "production";
const table = new sst.aws.Dynamo("Notes", {
fields: { userId: "string", noteId: "string" },
primaryIndex: { hashKey: "userId", rangeKey: "noteId" },
deletionProtection: isProd,
});
}
# Personal dev stage (default)
sst dev
# Deploy to staging
sst deploy --stage staging
# Deploy to production
sst deploy --stage production
See examples/deployment.md for multi-stage patterns with removal policies.
</patterns><decision_framework>
Decision Framework
Choosing an SST Component
What are you building?
|
+-- HTTP API
| +-- Simple routes with Lambda handlers --> sst.aws.ApiGatewayV2
| +-- Need WebSocket support --> sst.aws.ApiGatewayWebSocket
| +-- URL routing / CDN --> sst.aws.Router
|
+-- Data storage
| +-- Key-value / document data --> sst.aws.Dynamo
| +-- Relational data with SQL --> sst.aws.Postgres
| +-- File/blob storage --> sst.aws.Bucket
|
+-- Async processing
| +-- Point-to-point messaging --> sst.aws.Queue (SQS)
| +-- Fan-out to multiple subscribers --> sst.aws.Topic (SNS)
| +-- Scheduled tasks --> sst.aws.Cron
|
+-- Compute
| +-- Serverless function --> sst.aws.Function
| +-- Container workload --> sst.aws.Cluster + sst.aws.Service
| +-- Long-running background job --> sst.aws.Function (up to 15min)
|
+-- Full-stack frontend
+-- Next.js --> sst.aws.Nextjs
+-- Remix --> sst.aws.Remix
+-- Astro --> sst.aws.Astro
+-- SvelteKit --> sst.aws.SvelteKit
+-- SolidStart --> sst.aws.SolidStart
+-- Static HTML/JS --> sst.aws.StaticSite
When to Use Transforms vs Raw Pulumi
Need to set a property on an SST component?
|
+-- Property exists on the SST component args --> Use the SST property directly
|
+-- Property exists only on the underlying AWS resource --> Use transform
|
+-- Need to set a default across ALL instances of a component --> Use $transform()
|
+-- No SST component exists for this AWS service --> Use raw Pulumi resource
+-- Need to link it? --> Use sst.Linkable.wrap() or new sst.Linkable()
</decision_framework>
<red_flags>
RED FLAGS
High Priority Issues:
- Hardcoding ARNs, table names, or bucket names instead of using resource linking (
link+Resource.*) — defeats SST's type-safe wiring and breaks across stages - Sharing resource names across stages without
$app.stageprefix — causes resource conflicts and accidental cross-stage access - Putting secrets in
sst.config.tsor committed.envfiles instead of usingsst secret set— secrets leak to version control - Using
sst devfor shared environments (staging, production) — stubs proxy to a single developer's machine, breaking for everyone else - Creating raw Pulumi resources when an equivalent
sst.aws.*component exists — loses SST's linking, permissions, and defaults
Medium Priority Issues:
- Not setting
removal: "retain"andprotect: truefor production stages — accidentalsst removedeletes all data - Missing
/// <reference path="./.sst/platform/config.d.ts" />at top ofsst.config.ts— loses type checking for$app,$transform, etc. - Using
.envfiles for secrets instead ofsst secret—.envfiles aren't encrypted and must be managed manually per stage - Not running
sst deployafter finishingsst devsession — stubs remain deployed and Lambda invocations timeout
Common Mistakes:
- Forgetting that
sst devstubs persist after you stop the process — always redeploy or re-runsst dev - Using
$app.stagein runtime code — it's only available insst.config.ts, useResource.*or env vars for runtime stage awareness - Trying to use SST resource linking in client-side frontend code — links are server-side only (SSR functions, API routes)
- Expecting
sst devto emulate AWS locally — it doesn't; it proxies to real AWS resources in your account
Gotchas & Edge Cases:
- Pulumi Outputs cannot be used directly in string templates — use
$concat()or$interpolateinstead of template literals sst devmultiplexer starts frontends automatically — you don't need to runnext devorvite devseparately- FIFO queues require
.fifosuffix in names — SST handles this automatically but be aware when referencing externally .envand.env.<stage>files are loaded automatically —.envtakes precedence over stage-specific files- Frontend framework links (Next.js, Remix) only work server-side — client components cannot access
Resource.* - Layers specified in Function config are not applied during
sst dev— local execution skips layers - The
removalsetting inapp()controls what happens when you runsst remove—"remove"deletes resources,"retain"keeps them,"retain-all"keeps everything including logs
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST use resource linking (link + Resource.*) to connect components — NEVER hardcode ARNs, table names, or bucket names)
(You MUST use $app.stage for environment isolation — NEVER share resources across stages without explicit intent)
(You MUST use sst dev for local development — it provides live Lambda proxying with sub-10ms reloads against real AWS resources)
(You MUST use sst secret set for secrets — NEVER put secrets in sst.config.ts, .env files committed to git, or environment variables)
(You MUST use transform to customize underlying resources — NEVER reach for raw Pulumi resources when an SST component exists)
Failure to follow these rules will cause cross-stage resource conflicts, leaked secrets, broken type safety, and unnecessary infrastructure complexity.
</critical_reminders>
What ships with it: 4 files
31.4 KB alongside SKILL.md
examples/
- api-data.md8.1 KB
- core.md8.0 KB
- deployment.md9.3 KB
- reference.md5.9 KB