在 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。