在 AWS 上交付全栈应用时,最好不要把 AWS Console 当成真相来源。Frontend、secrets、domains 与 stage rules 都应该用 TypeScript 写在应用旁边,经 pull request 审视,并在每个环境以同样方式套用。
SST 用代码定义应用——通常从单一 sst.config.ts 开始——并自动化底层 AWS resources。本站是 Bun + Turborepo monorepo,Next.js 跑在 OpenNext 上,并有 local、shared preview 与 production 的 stages。
三种 infra 故事分开处理:
- 目前已部署 —
sst.config.ts只 import Next.js / OpenNext stack。 - 已在 repo 里定义,但尚未 import — container API infra(
Vpc→Cluster→Service+Router)放在packages/infra,并在run()里保持注释,直到该 stack 需要部署。 - 其他地方的相关模式 — 用 Lambda + API Gateway 做 Hono API 见 用 Hono、Drizzle、Zod OpenAPI 与 SST 打造 Backend APIs。那篇笔记并不是本站
sst.config.ts正在跑的内容。
1. 为什么这套 stack 选 SST
SST 让开发者可以用 Components 定义应用功能,而不必亲手组装每一个低阶 resource。
- 较高阶的 components,这里用到:
sst.aws.Nextjs、sst.Secret,以及(当 API module 接上时)sst.aws.Service、sst.aws.Router、sst.aws.Vpc与sst.aws.Cluster。 - Resource linking,让 runtime 代码通过 typed
ResourceSDK 读取基础设施,而不是 hardcoded names 与 ARNs。 sst dev作为统一的本地环境:infra watcher、来自同一 CLI 的 frontend(以及之后的 container)devprocesses,再加上当 stage 里有 Lambda handlers 时的 Live。
本站:经 OpenNext 的 Next.js、以 stage 为基础的 domains、非 prod 的 edge Basic Auth,以及与 packages/infra 分开的应用 packages。SST 与 Pulumi 或 CDK for Terraform 的比较见 SST FAQ。
2. SST 与其他 IaC 的比较
这些工具都共享 infrastructure as code。SST 面向 developers;CDKTF 与 Pulumi 主要面向 DevOps engineers。SST 底层仍使用 open-source Pulumi 与 bridged Terraform providers;它不需要 Pulumi account,应用 state 也留在团队自己的 cloud account(SST docs)。
| Tool | Mental model | Strength | 为什么 SST 适合这里的 app stacks |
|---|---|---|---|
| Terraform / OpenTofu | Declarative HCL,以 provider 为中心 | 通用、成熟的 state 与 workflow;适合组织级 platform teams | App 与 infra 仍然分开;对这个 monorepo 没有 first-class Live、linking,或 Nextjs DX |
| AWS CDK | TypeScript constructs → CloudFormation | 深度 AWS 覆盖与 Constructs 生态 | AWS-native modeling 很强;对这个 workflow 的统一 app loop(linking、sst dev、frontend + backend multiplexer)较弱 |
| Pulumi / CDKTF | 用真实语言写的通用 IaC | Providers 灵活;适合 platform team 拥有整支 program 的情况 | SST 建在 Pulumi 之上,但加上 app components、linking 与 sst dev,不必为每个 feature 写完整 Pulumi program |
| Serverless Framework | 聚焦 serverless apps 的 framework | 熟悉的 Lambda packaging | 比这里用到的全栈 Next/OpenNext、containers 与 stage workflows 更窄 |
| Vercel / PaaS | Git push → hosted platform | 快速 frontend DX,几乎不用碰 AWS 表面 | 只需要 managed frontend 时很强;当需要以 TypeScript 拥有 AWS resources、domains、secrets 与可选的 ECS/API 时选 SST |
- SST components 编码常见 app patterns,仍允许在需要更低阶控制时使用
transform加上 150+ providers。 - Linking 补上 Terraform 或 CDK 通常靠手写 env vars 与 IAM 填补的 runtime 缺口。
sst dev是产品功能,而不是自己组装的本地 stack。 - SST 仍然有 state——本地加上 backup bucket——所以 managed resources 不应在 Console 人手编辑(Basics)。那份 state 的 backup,以及何时 snapshot 不是 failover,见 System Design 里的 Disaster Recovery。
当 platform team 已经用 Terraform 或 OpenTofu 拥有 shared networking、当 Pulumi 或 Terraform 是团队多云 control planes 的语言,或当 CloudFormation-native CDK construct libraries 是招聘与 review 表面时,SST 并不适合。
3. 项目形状:sst.config.ts 与 packages/infra
SST 支持 drop-in mode——在 Next.js app 旁边放单一 sst.config.ts——以及 monorepo,config 留在 root,基础设施拆成 modules。这个项目用 monorepo 形状。
sst.config.ts app name, region, protect / removal, imports
packages/infra/ Next.js, secrets, domain, edge, optional API/VPC
apps/web Next.js site
apps/api Hono / Mastra API
packages/* shared auth, db, content, design systemConfig 文件定义 app identity 与安全规则。run function 加载 infra modules。今天只 import Next.js;API module 保持注释,直到该 stack 需要部署:
export default $config({
app(input) {
return {
name: "my-app",
removal: input?.stage === "production" ? "retain" : "remove",
protect: ["production"].includes(input?.stage),
home: "aws",
providers: {
aws: {
region: "us-east-1",
},
},
}
},
async run() {
// await import("./infra/api")
await import("./infra/nextjs")
},
})nextjs— OpenNext 部署与 domains(今天已 import)secrets— stage secrets,例如 edge Basic Auth credentials,以及 API 路径的 database 与 auth secretsdomain/edge— apex domain 与非 prod 的 edge Basic Authapi/router/vpc/cluster— container API 路径,已定义但尚未 import
业务逻辑不放在这些文件里。Infra modules 创建并 link resources;应用 packages 消费它们。
4. 这套 Stack 里的 Components
本站用 sst.aws.Nextjs 部署。Production 用 apex domain;其他 stages 用 {stage}.example.com。
const isProd = $app.stage === "production"
const domain = "example.com"
export const nextjs = new sst.aws.Nextjs("Web", {
path: "apps/web",
domain: {
name: isProd ? domain : `${$app.stage}.${domain}`,
redirects: isProd ? [`www.${domain}`] : [],
},
warm: isProd ? 1 : 0,
environment: {
NEXT_PUBLIC_SITE_URL: `https://${domain}`,
SST_STAGE: $app.stage,
},
openNextVersion: "4.0.3",
edge,
dev: {
command: "bun run dev",
directory: "apps/web",
url: "http://localhost:3000",
},
})- Production 保留一个 warm server instance;非 prod 用
warm: 0。edgeprop 接上非 prod Basic Auth。devblock 告诉sst dev如何启动本地 Next process。 - Secrets 是 first-class resources,不是松散的
.env文件:sst.Secret("Username")、Password、DatabaseUrl、BetterAuthSecret、AiGatewayApiKey。 - 当 API module 被 import 时,路径是
Vpc→Cluster→Service,再用Router做api.example.com或{stage}.api.example.com。在启用await import("./infra/api")之前,那个 stack 不会部署。 - 另一种形状——Lambda 在 API Gateway 后面,加上 Lambda authorizer——是 用 Hono、Drizzle、Zod OpenAPI 与 SST 打造 Backend APIs 里的模式。那用
sst.aws.Function与sst.aws.ApiGatewayV2。它不是本站 config 目前加载的基础设施。
5. 用 Linking 取代 Hardcoded Env
Resource linking 是基础设施与 runtime 之间的桥。创建一个 resource,放进 link,再用 SDK 读取。
- Linking 注入 values、生成 types(
sst-env.d.ts),并在 component 支持的地方授予 permissions。 - 本站今天,Next.js stack 通过
edgeconfiguration 拉取 edge Basic Auth credentials。Web app 本身并不为 database 读取Resource.*。 - 当 API module 被 import 时,secrets 会被 link 进 container service。
import { Resource } from "sst"
const client = postgres(Resource.DatabaseUrl.value, {
ssl: "require",
})- Linked values 只在 server 侧可用。Client components 只能看见明确传进去的东西。
- 对需要 stage secrets 的 CLIs——Drizzle migrations、Better Auth schema generation——
sst shell加载 linked stage environment,不必发明第二条 secrets 路径。
6. Stages 作为 DevOps 单位
在 SST 里,stage 是一个环境:应用的一份 namespaced copy。
| Stage | Purpose | Domain pattern |
|---|---|---|
local / personal | 日常 sst dev | 本地 Next URL;该 stage 的 cloud resources |
dev | Shared preview | dev.example.com |
production | Live site | example.com |
- Production 受保护。意外的
sst remove不应抹掉关键数据,所以 config 在 production 上用protect与removal: "retain"(removal policies)。 - 非 production stages 通过 edge
viewerRequestinjection 拿到 CloudFront Basic Auth,所以 preview URLs 默认不公开。 - Credentials 留在本地 AWS credential chain(profile 或 SSO session)。SST 部署进那个 account 与 region。Next.js 与 secret resources 不是靠在 Console 点出来的。
aws sso login # refresh AWS credentials
sst dev --stage local # personal / local stage
sst deploy --stage dev # shared preview
sst deploy --stage production7. 本地 Workflow:sst dev、Live 与 Mode Discipline
sst dev 是本地 control plane。
- 一个会部署基础设施变更的 watcher。
- Next.js
devblock——本地 Next,link 到该 stage 已部署的 resources。 - 之后,当 API module 被 import 时,container
devcommand,以及可选的 tunnel 到 VPC resources。 - Live——AWS 里把请求 proxy 到本机的 stub Lambdas——对 Lambda-heavy stages 最重要,包括 backend APIs 笔记里的 Function / API Gateway 模式。在本站只 import OpenNext 时,它没那么核心。
sst dev 属于 personal 或 local stage。Shared dev 与 production 用 sst deploy。Shared URL 意味着部署一个真正的 stage。用 breakpoints 调试 Lambda handler 意味着在 personal stage 上用 Live——调试 Node handlers 时搭配 VS Code Auto Attach。
Failure: 在同一个 stage 上在 Live stubs 与真正 deploys 之间翻转。若 CLI 被杀掉,stubs 可能留下,remote invokes 会超时等待本机(Live quirks)。
8. Production 安全与 CI 边界
IaC 只有在 state 与流程保持诚实时才有用。
- 不要在 Console 编辑 SST 管理的 resources。SST 会依 config 对 state 套用 diffs;人手编辑会让 state drift(Basics)。
- 保护 production:用
protect与removal: "retain"。API 路径用的 Postgres 是经sst.Secret的外部 URL,不是这个 config 创建的sst.aws.Postgres。 - 先验证,再在 CI 部署。 GitHub Actions 先跑 install、lint、format check、typecheck、tests 与 build。只有这些 checks 成功后,workflow 才对
dev或production跑sst deploy。 - 本地
deploy:dev/deployscripts 仍适合刻意的一次性 deploys。默认路径是 CI:checks 全绿,再 deploy。 - SST Console 是另一种取得 git-push autodeploy 的方式。本站用 GitHub Actions 做 verify-then-
sst deploy序列。
Tenant isolation 与 SaaS 边界设计是另一个问题——见 用 Hono、Better Auth、Drizzle 与 Postgres RLS 打造 Multi-Tenant 后端。
9. Mental Model
sst.config.ts
→ packages/infra/nextjs (imported today)
→ Nextjs / OpenNext + edge Basic Auth secrets
→ packages/infra/api (defined, not imported)
→ Vpc / Cluster / Service / Router + linked secrets
→ link (when a consumer is linked)
→ Resource.* in app runtime
→ sst shell for CLIs
stages: local | dev | production
local: sst dev
ci: checks → tests → build → sst deploy --stage …SST 让 AWS infrastructure 成为可 review 的 TypeScript,并放在应用旁边。当问题是组织级 platform ownership 时,Terraform、CDK 或 Pulumi 仍然更合适。目前的 component 与 CLI 细节,从 SST docs 开始。关于 Lambda 或 Fargate 上的 Hono API,继续看 用 Hono、Drizzle、Zod OpenAPI 与 SST 打造 Backend APIs。