{"slug":"infra-iac-sst","title":"infra-iac-sst","summary":"SST (Ion) infrastructure-as-code — TypeScript-first serverless on AWS with Pulumi, resource linking, and live Lambda dev","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-09-29T15:28:08.612288Z","repo":{"url":"https://github.com/agents-inc/skills","stars":24,"forks":8,"license":"MIT","updatedAt":"2026-09-07T17:50:55Z"},"bodyHtml":"<hr>\n<h2>name: infra-iac-sst\ndescription: SST (Ion) infrastructure-as-code — TypeScript-first serverless on AWS with Pulumi, resource linking, and live Lambda dev</h2>\n<h1>SST (Ion) Patterns</h1>\n<blockquote>\n<p><strong>Quick Guide:</strong> SST v3 (Ion) is TypeScript-first infrastructure-as-code for AWS, powered by Pulumi/Terraform (not CDK/CloudFormation). Define your entire app in <code>sst.config.ts</code> using high-level components (<code>sst.aws.Function</code>, <code>sst.aws.ApiGatewayV2</code>, <code>sst.aws.Bucket</code>, <code>sst.aws.Dynamo</code>, etc.). Use <strong>resource linking</strong> (<code>link: [bucket]</code> + <code>Resource.MyBucket.name</code>) for type-safe, permission-aware access between components. Use <code>sst dev</code> for live Lambda development with sub-10ms reloads. Use <code>$app.stage</code> for multi-environment isolation. Use <code>transform</code> to customize underlying Pulumi resources.</p>\n</blockquote>\n<hr>\n<p>&lt;critical_requirements&gt;</p>\n<h2>CRITICAL: Before Using This Skill</h2>\n<blockquote>\n<p><strong>All code must follow project conventions in CLAUDE.md</strong> (kebab-case, named exports, import ordering, <code>import type</code>, named constants)</p>\n</blockquote>\n<p><strong>(You MUST use resource linking (<code>link</code> + <code>Resource.*</code>) to connect components — NEVER hardcode ARNs, table names, or bucket names)</strong></p>\n<p><strong>(You MUST use <code>$app.stage</code> for environment isolation — NEVER share resources across stages without explicit intent)</strong></p>\n<p><strong>(You MUST use <code>sst dev</code> for local development — it provides live Lambda proxying with sub-10ms reloads against real AWS resources)</strong></p>\n<p><strong>(You MUST use <code>sst secret set</code> for secrets — NEVER put secrets in <code>sst.config.ts</code>, <code>.env</code> files committed to git, or environment variables)</strong></p>\n<p><strong>(You MUST use <code>transform</code> to customize underlying resources — NEVER reach for raw Pulumi resources when an SST component exists)</strong></p>\n<p>&lt;/critical_requirements&gt;</p>\n<hr>\n<h2>Examples</h2>\n<ul>\n<li><a href=\"examples/core.md\">Core Patterns</a> — sst.config.ts structure, Function, resource linking, $app globals, secrets, multi-stage</li>\n<li><a href=\"examples/api-data.md\">API &amp; Data</a> — ApiGatewayV2, Dynamo, Bucket, Queue, Topic, Cron, authorization</li>\n<li><a href=\"examples/deployment.md\">Deployment &amp; DevOps</a> — sst deploy, CI/CD, removal policies, transforms, Vpc, Cluster, frontend frameworks</li>\n<li><a href=\"reference.md\">Quick Reference</a> — CLI commands, component cheat sheet, global helpers, named constants</li>\n</ul>\n<hr>\n<p><strong>Auto-detection:</strong> 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</p>\n<p><strong>When to use:</strong></p>\n<ul>\n<li>Defining AWS infrastructure in TypeScript with high-level components</li>\n<li>Deploying serverless applications (Lambda, API Gateway, DynamoDB, S3, SQS, SNS)</li>\n<li>Deploying full-stack apps (Next.js, Remix, Astro, SvelteKit, SolidStart on AWS)</li>\n<li>Setting up live Lambda development with real AWS resources</li>\n<li>Managing multi-stage environments (dev, staging, production)</li>\n<li>Connecting infrastructure components with type-safe resource linking</li>\n</ul>\n<p><strong>When NOT to use:</strong></p>\n<ul>\n<li>Multi-cloud infrastructure spanning many providers (SST is AWS-focused with limited Cloudflare support)</li>\n<li>Existing Terraform/Pulumi codebases where SST abstraction adds no value</li>\n<li>Projects that need container-only deployments without serverless components</li>\n</ul>\n<p><strong>Key patterns covered:</strong></p>\n<ul>\n<li><code>sst.config.ts</code> structure (<code>app()</code> + <code>run()</code> functions)</li>\n<li>Resource linking: <code>link</code> property + <code>Resource.*</code> SDK</li>\n<li>Live Lambda development with <code>sst dev</code></li>\n<li>AWS components: Function, ApiGatewayV2, Dynamo, Bucket, Queue, Topic, Cron</li>\n<li>Frontend deployments: Nextjs, Remix, Astro, StaticSite</li>\n<li>Multi-stage isolation with <code>$app.stage</code></li>\n<li>Transforms for customizing underlying Pulumi resources</li>\n<li>Secrets management with <code>sst secret</code></li>\n<li>Custom linkables with <code>sst.Linkable</code> and <code>Linkable.wrap</code></li>\n<li>Global helpers: <code>$app</code>, <code>$dev</code>, <code>$concat</code>, <code>$interpolate</code>, <code>$resolve</code>, <code>$transform</code></li>\n</ul>\n<hr>\n\n<hr>\n\n<hr>\n<p>&lt;decision_framework&gt;</p>\n<h2>Decision Framework</h2>\n<h3>Choosing an SST Component</h3>\n<pre><code>What are you building?\n  |\n  +-- HTTP API\n  |     +-- Simple routes with Lambda handlers --&gt; sst.aws.ApiGatewayV2\n  |     +-- Need WebSocket support --&gt; sst.aws.ApiGatewayWebSocket\n  |     +-- URL routing / CDN --&gt; sst.aws.Router\n  |\n  +-- Data storage\n  |     +-- Key-value / document data --&gt; sst.aws.Dynamo\n  |     +-- Relational data with SQL --&gt; sst.aws.Postgres\n  |     +-- File/blob storage --&gt; sst.aws.Bucket\n  |\n  +-- Async processing\n  |     +-- Point-to-point messaging --&gt; sst.aws.Queue (SQS)\n  |     +-- Fan-out to multiple subscribers --&gt; sst.aws.Topic (SNS)\n  |     +-- Scheduled tasks --&gt; sst.aws.Cron\n  |\n  +-- Compute\n  |     +-- Serverless function --&gt; sst.aws.Function\n  |     +-- Container workload --&gt; sst.aws.Cluster + sst.aws.Service\n  |     +-- Long-running background job --&gt; sst.aws.Function (up to 15min)\n  |\n  +-- Full-stack frontend\n        +-- Next.js --&gt; sst.aws.Nextjs\n        +-- Remix --&gt; sst.aws.Remix\n        +-- Astro --&gt; sst.aws.Astro\n        +-- SvelteKit --&gt; sst.aws.SvelteKit\n        +-- SolidStart --&gt; sst.aws.SolidStart\n        +-- Static HTML/JS --&gt; sst.aws.StaticSite\n</code></pre>\n<h3>When to Use Transforms vs Raw Pulumi</h3>\n<pre><code>Need to set a property on an SST component?\n  |\n  +-- Property exists on the SST component args --&gt; Use the SST property directly\n  |\n  +-- Property exists only on the underlying AWS resource --&gt; Use transform\n  |\n  +-- Need to set a default across ALL instances of a component --&gt; Use $transform()\n  |\n  +-- No SST component exists for this AWS service --&gt; Use raw Pulumi resource\n        +-- Need to link it? --&gt; Use sst.Linkable.wrap() or new sst.Linkable()\n</code></pre>\n<p>&lt;/decision_framework&gt;</p>\n<hr>\n<p>&lt;red_flags&gt;</p>\n<h2>RED FLAGS</h2>\n<p><strong>High Priority Issues:</strong></p>\n<ul>\n<li>Hardcoding ARNs, table names, or bucket names instead of using resource linking (<code>link</code> + <code>Resource.*</code>) — defeats SST's type-safe wiring and breaks across stages</li>\n<li>Sharing resource names across stages without <code>$app.stage</code> prefix — causes resource conflicts and accidental cross-stage access</li>\n<li>Putting secrets in <code>sst.config.ts</code> or committed <code>.env</code> files instead of using <code>sst secret set</code> — secrets leak to version control</li>\n<li>Using <code>sst dev</code> for shared environments (staging, production) — stubs proxy to a single developer's machine, breaking for everyone else</li>\n<li>Creating raw Pulumi resources when an equivalent <code>sst.aws.*</code> component exists — loses SST's linking, permissions, and defaults</li>\n</ul>\n<p><strong>Medium Priority Issues:</strong></p>\n<ul>\n<li>Not setting <code>removal: \"retain\"</code> and <code>protect: true</code> for production stages — accidental <code>sst remove</code> deletes all data</li>\n<li>Missing <code>/// &lt;reference path=\"./.sst/platform/config.d.ts\" /&gt;</code> at top of <code>sst.config.ts</code> — loses type checking for <code>$app</code>, <code>$transform</code>, etc.</li>\n<li>Using <code>.env</code> files for secrets instead of <code>sst secret</code> — <code>.env</code> files aren't encrypted and must be managed manually per stage</li>\n<li>Not running <code>sst deploy</code> after finishing <code>sst dev</code> session — stubs remain deployed and Lambda invocations timeout</li>\n</ul>\n<p><strong>Common Mistakes:</strong></p>\n<ul>\n<li>Forgetting that <code>sst dev</code> stubs persist after you stop the process — always redeploy or re-run <code>sst dev</code></li>\n<li>Using <code>$app.stage</code> in runtime code — it's only available in <code>sst.config.ts</code>, use <code>Resource.*</code> or env vars for runtime stage awareness</li>\n<li>Trying to use SST resource linking in client-side frontend code — links are server-side only (SSR functions, API routes)</li>\n<li>Expecting <code>sst dev</code> to emulate AWS locally — it doesn't; it proxies to real AWS resources in your account</li>\n</ul>\n<p><strong>Gotchas &amp; Edge Cases:</strong></p>\n<ul>\n<li>Pulumi Outputs cannot be used directly in string templates — use <code>$concat()</code> or <code>$interpolate</code> instead of template literals</li>\n<li><code>sst dev</code> multiplexer starts frontends automatically — you don't need to run <code>next dev</code> or <code>vite dev</code> separately</li>\n<li>FIFO queues require <code>.fifo</code> suffix in names — SST handles this automatically but be aware when referencing externally</li>\n<li><code>.env</code> and <code>.env.&lt;stage&gt;</code> files are loaded automatically — <code>.env</code> takes precedence over stage-specific files</li>\n<li>Frontend framework links (Next.js, Remix) only work server-side — client components cannot access <code>Resource.*</code></li>\n<li>Layers specified in Function config are not applied during <code>sst dev</code> — local execution skips layers</li>\n<li>The <code>removal</code> setting in <code>app()</code> controls what happens when you run <code>sst remove</code> — <code>\"remove\"</code> deletes resources, <code>\"retain\"</code> keeps them, <code>\"retain-all\"</code> keeps everything including logs</li>\n</ul>\n<p>&lt;/red_flags&gt;</p>\n<hr>\n<p>&lt;critical_reminders&gt;</p>\n<h2>CRITICAL REMINDERS</h2>\n<blockquote>\n<p><strong>All code must follow project conventions in CLAUDE.md</strong> (kebab-case, named exports, import ordering, <code>import type</code>, named constants)</p>\n</blockquote>\n<p><strong>(You MUST use resource linking (<code>link</code> + <code>Resource.*</code>) to connect components — NEVER hardcode ARNs, table names, or bucket names)</strong></p>\n<p><strong>(You MUST use <code>$app.stage</code> for environment isolation — NEVER share resources across stages without explicit intent)</strong></p>\n<p><strong>(You MUST use <code>sst dev</code> for local development — it provides live Lambda proxying with sub-10ms reloads against real AWS resources)</strong></p>\n<p><strong>(You MUST use <code>sst secret set</code> for secrets — NEVER put secrets in <code>sst.config.ts</code>, <code>.env</code> files committed to git, or environment variables)</strong></p>\n<p><strong>(You MUST use <code>transform</code> to customize underlying resources — NEVER reach for raw Pulumi resources when an SST component exists)</strong></p>\n<p><strong>Failure to follow these rules will cause cross-stage resource conflicts, leaked secrets, broken type safety, and unnecessary infrastructure complexity.</strong></p>\n<p>&lt;/critical_reminders&gt;</p>\n","files":[{"path":"examples/api-data.md","sizeBytes":8266,"isText":true},{"path":"examples/core.md","sizeBytes":8239,"isText":true},{"path":"examples/deployment.md","sizeBytes":9743,"isText":true},{"path":"reference.md","sizeBytes":7921,"isText":true},{"path":"SKILL.md","sizeBytes":17945,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"notes-only","suspicious":0,"notes":24,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-09-29T15:30:27.224992Z","sha256":"03374ADEBA8ACBC627ADD2D87C5C7F6246249DB3FB0AF91988B0EC6B1A38178D","sizeBytes":18753},"review":null,"source":{"repositoryUrl":"https://github.com/agents-inc/skills","path":"dist/plugins/infra-iac-sst/skills/infra-iac-sst","license":"MIT","commit":"3a51ef571e996b18294bf776d53dbdad26de0617","subtreeSha":"C370BFF9EBDDA18247A9D88444CC3A3331A45326E8EB2FC66990B723777B2BA2","lastSyncedAt":"2026-09-29T15:27:48.914434Z"},"reviewedAt":"2026-09-29T15:35:26.669203Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/agents-inc/skills/tree/main/dist/plugins/infra-iac-sst/skills/infra-iac-sst"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install agents-inc-skills@llmmart"},{"target":"git","command":"git clone https://github.com/agents-inc/skills.git"}]}