我这个站点一开始放在 AWS Amplify 上,理由其实很朴素:我已经用着 AWS 的一些其它服务——S3 存媒体、Route 53 管域名——既然账号都在那里,顺手用 Amplify 把全栈 App 部署起来是最省心的方案。前几个月也确实如此,推一条 commit、构建、上线,整套流程对一个个人项目来讲足够好用。
让我开始重新审视这个选择的,不是某次戏剧性的事故,而是随着站点持续迭代、功能一点一点叠上去之后,Amplify 那种"已经够用了"的边界慢慢逼近的那种感觉。一个人维护的项目,没有理由也没有动机去开它的付费档,可它免费档能提供的空间又确实越来越紧。直到接连出了几次部署上的问题,我才下定决心把整个站搬到 Vercel。
真正促成迁移的那几次部署
最早的一道坎其实非常小,是 pnpm 的版本。我 amplify.yml 里写的是 corepack prepare pnpm@latest --activate,这种"永远用最新"的偷懒写法在 CI 里是个隐患。某次 pnpm 发了新大版本,Amplify Standard 镜像里的 Node 20 配上新版 Corepack 直接抛出 ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING,构建挂掉。教训是 CI 永远不要相信 @latest,最后我把 pnpm 版本通过 packageManager 字段写死在 package.json 里。
真正不可调和的是构建容器的内存上限。Amplify Standard 构建机给的是 8 GB / 4 vCPU。当我的项目里同时存在 three.js、langchain、tiptap、AWS SDK 这些不算轻的依赖,又新加了几个内容偏重的页面之后,Next.js 在 Collecting page data 阶段会按 CPU 数 fork 出 3 个 worker,每个 worker 都要完整加载一遍模块图。三份模块图加起来超过 8 GB,构建直接 OOM。
这件事的尴尬之处在于:我可以在 next.config.mjs 里把 worker 数量限制为 1、再给 Node 加 --max-old-space-size=6144 的堆上限来勉强挤进去,但这本质上是把构建从"并行"退化成"串行"换取空间。再加一个稍微重一点的依赖、或者一两个新页面,又会顶到天花板。要真正解决这个问题,唯一的办法是升级到 Amplify Large 构建付费功能。对一个自用的个人项目来说,每月为构建容器单独开支不太合理。这是我下决心搬家的直接触发点。
顺便说一下,这不是我第一次在 Amplify 上吃构建空间的亏。之前在公司维护别的项目时也遇到过类似的事,Amplify 对单个 SSR Lambda 有 224 MB 的构建产物大小上限,超出就部署失败。为了挤进这个上限,那时候我们要花相当大的力气去裁剪产物:把不必要的依赖踢出 trace、移大文件到 S3、调 output: 'standalone' 之后再手动 cp -r 拼凑目录。这些活儿现在回头看,全部是平台自己的限制造出来的工作量。
搬到 Vercel 的过程
Vercel 这边的体验是另一种节奏。CLI 装好、vercel link 选了 GitHub 上现成的仓库、把那些原本通过 env | grep 走私进 .env.production 的环境变量贴进 Dashboard,然后点 Deploy。同一份代码,Amplify 上爆掉的构建,Vercel 上一气呵成。我把之前为了在 8 GB 容器里求生而加的 worker / 堆大小限制全部从 next.config.mjs 里删掉,构建反而更快了,因为 worker 又可以正常并发。
DNS 是迁移里唯一真正算"干活"的一步。我的域名仍然在 Route 53,所以处理也很直接:apex A 记录从指向 Amplify 的 CloudFront alias 改成 Vercel 给的 IP,www CNAME 改成 Vercel 项目专属的域名;切换前把 TTL 降到 60 秒方便回滚,稳定之后再调回正常值。整个过程没有停机感,全球的 DNS 几分钟之内就传播到了。
切完之后我才发现 Vercel 内置的几个东西原来是默认免费的——Speed Insights、Analytics、Preview Deployments、Function 日志,全部不需要额外配置就直接出现在 Dashboard 上。这种"装好就有"的感觉,跟在 AWS 体系里要么自己拼 CloudWatch 仪表盘、要么按 GB 付钱开 X-Ray 是两个世界。
一个值得单独讲的 AWS 账单陷阱
偶然情况我去翻 AWS 账单,发现一行 $8/月的 WAF 费用,而它跟 Amplify 完全没有关系。它挂在另一个 CloudFront distribution 上,那是我给一个副项目的媒体存储做的 CDN。问题在于:那个 CloudFront 被 AWS 自动绑进了一个名叫 "Free 计划" 的定价方案,这个计划本身是 $0/月不错,但它强制要求这个 distribution 必须挂一个 Web ACL,而 Web ACL 本身是按标准价收费的($5 的 ACL 费 + $1/条规则)。
也就是说,这个"免费"的 CDN 计划,依赖一个不免费的 WAF 资源。而你在使用免费部分的同时,实际上一直在为它的"必需依赖"付钱。AWS 控制台里 WAF 那个面板甚至会一边告诉你"包含在 Free 计划里",一边按月收你 $8。我去尝试 disassociate WAF 的时候,系统直接拒绝,理由是"订阅了定价计划的 distribution 必须有 web ACL"。这种内建的依赖陷阱才是 AWS 复杂计费里最让人头疼的部分:你以为自己在用免费档,账单跟你说不是。
这不是 Amplify 的锅,但属于"在 AWS 生态里待得越久越容易撞上的事"。离开生态以后,账单确实清爽了不少。
一些回头看的对比
如果你的整个团队和栈本来就深度绑定在 AWS 上,你有 RDS、有自己的 VPC、IAM 已经划分得很细。。。那 Amplify 提供的是一个统一生态里的统一架构,它的价值是无可替代的。企业团队选 Amplify 通常是这个理由,不是因为它在 Next.js 这块表现得有多突出。
但放到一个像我这样的个人开发者身上,价值天平就完全反过来。我没有 VPC 要管、没有 IAM 角色要审计、没有团队规范要执行;我只想推 commit、看预览、上线。在这个画像下,Vercel 的几个优势变得很压倒性:构建容器的默认配置就更合理、Next.js 的新特性是第一时间能用上的、可观测性是装好就有的、Preview URL 每个 PR 自动给一个、AI Gateway 这种东西直接换个 env var 就接上了。
迁完之后我完全不再需要为构建大小这件事操心。新加依赖、加页面、加功能,构建照常通过;想看页面加载快不快,Speed Insights 直接给数;想看 Function 执行情况,Dashboard 翻一下就有。这种"基础设施退到背景里"的感觉,是我作为一个想专心写代码的人最想要的东西。
一句话总结
如果你和我一样,是一个在 AWS 生态里慢慢长大、然后慢慢被它的边界推到不舒服的人——那 Vercel 值得你认真考虑一次。迁移的成本是真的、但是有边界的;继续跟一个不太合适的托管平台搏斗的成本,是没有边界的。
写作时的栈:Next.js 16.1 App Router、Turbopack 生产构建、pnpm 10.27、MongoDB Atlas、S3 媒体、OpenAI 经 Vercel AI Gateway、部署在 Vercel Fluid Compute、DNS 留在 Route 53。