本地 npm run build 是绿的,Vercel 却显示 Build failed。烦人,但失败模式就那么几种:7 个类别覆盖约 95% 的真实失败,build 日志会告诉你是哪一类——前提是你知道往哪看。本文给出每一类的精确日志字符串、一条诊断命令、一处配置修复。文中数字以 2026 年 6 月为准。
TL;DR
- 打开失败的 deployment,点 Building,滚到进程退出前最后一行红色。那行约 90% 的情况就是真因。
- build 跑在干净的 Linux 容器里,默认 Node 24.x(可固定到 20.x 或 22.x)。你的 Mac 跑的是另一个 Node 版本、有你的环境变量、且文件路径大小写不敏感。绝大多数失败就出在这三个差异上。
- 每个 build 容器有 8192 MB(8 GB)内存,并且每个套餐(包括 Pro)都是 45 分钟硬超时——这两个上限不会因为单纯升级席位而提高。
怎么读那行日志
把失败行对到一个类别,再跳到下面对应的修复。
日志字符串 → 类别
"Cannot find module" / "Module not found" → 依赖漂移或路径大小写
"process is not defined" / 环境变量为 undefined → build 阶段缺环境变量
"Type error:" / "tsc" 非零退出 → TypeScript 比本地严
"Killed" / "SIGKILL" / "heap out of memory" → 内存不足(OOM)
"No Output Directory named ... found" → 框架预设 / 输出目录错
"Command failed with exit code 1" → 笼统报错:读它上面那行
build 跑约 45 分钟后停 → 超时(Hobby 和 Pro 一样)
"昨天能 build 今天挂,代码没动" → 缓存陈旧或依赖漂移
7 类原因和对应修复
1. Node 版本不一致
Vercel 新项目默认 Node 24.x(截至 2026 年 6 月,可用主版本是 24.x、22.x、20.x)。如果你的代码依赖本地 Node 有、而 24.x 砍掉的东西,或者你在 20 上开发、某个依赖却需要 22+,build 就和本地分叉了。直接在 package.json 里固定版本,免得 dashboard 设置悄悄变动:
{
"engines": { "node": "24.x" },
"scripts": { "build": "astro build" }
}
Vercel 读 engines.node,部署该主版本的最新补丁版。Project Settings 下拉框(Settings → Build and Deployment → Node.js Version)是没写 engines 时的兜底。两者选其一,别同时较劲。
2. 缺环境变量
典型症状是 process is not defined,或某个值在 build 阶段(而非运行时)读出来是 undefined。Vercel 不会拷贝你本地的 .env——变量存在 dashboard 里,按环境分别配置。只加到 Preview 没加到 Production 的变量,只在生产部署时失败,这正是”我 PR 上能 build、合到 main 就挂”的常见原因。
vercel env add OPENAI_API_KEY production
# 按提示粘贴 secret
vercel env add SITE_URL production
# https://yourdomain.com
vercel --prod # 触发一次干净部署
Dashboard 路径:Settings → Environment Variables,给每一个会跑 build 的环境都加上变量。Next.js 里浏览器要读的变量必须以 NEXT_PUBLIC_ 开头、且在 build 时就存在——缺一个 NEXT_PUBLIC_* 是 exit code 1 的高频成因。
3. Vercel 上 TypeScript 比本地严
你看到 Type error: 和 tsc 非零退出。通常是编辑器默默放过了什么,或本地 skipLibCheck 把问题盖住了。先在本地复现 Vercel 实际跑的命令:
npx tsc --noEmit
# tsconfig.json 里 "strict": true 时,这会暴露 Vercel 看到的同样错误
先改代码。只有确认 strictness 是误开时才放松配置——而且要精准放松,不要直接关掉整个 strict:
{
"compilerOptions": {
"strict": true,
"skipLibCheck": true,
"noUncheckedIndexedAccess": false
}
}
4. 依赖漂移或路径大小写 bug
本地绿、Vercel 报 Cannot find module 或 Module not found,通常是提交到 git 的 lockfile 和实际安装的不一致。刷新它:
rm -rf node_modules package-lock.json
npm install
git add package-lock.json
git commit -m "fix: refresh lockfile"
然后在 Vercel:Deployments → Redeploy → 取消勾选 “Use existing build cache”,强制干净安装。还要留意更隐蔽的那种:macOS 路径大小写不敏感,Vercel 的 Linux 容器大小写敏感。import Foo from './Components/Foo' 在你的 Mac 上能解析,但若文件夹实际叫 components,在 Vercel 上就挂。把 import 里和真实路径大小写不符的地方 grep 出来。
5. 内存不足(“Killed” / SIGKILL)
每个 build 容器上限 8192 MB(8 GB)。build 超过这个量时,Node 会被 SIGKILL 杀掉,日志显示 Killed 或 JavaScript heap out of memory,往往没有别的上下文。按顺序用两招:
第一招,把 Node 的堆抬到接近容器上限但留出余量。Vercel 自己建议留点空间,所以目标设 6 GB 而非 8:
{
"scripts": {
"build": "NODE_OPTIONS='--max-old-space-size=6144' next build"
}
}
第二招,在 build 本身里压低峰值内存。Astro 可以串行生成页面,别什么都内联:
// astro.config.mjs
export default defineConfig({
build: {
concurrency: 1, // 串行生成页面,降低峰值内存
inlineStylesheets: 'never',
},
image: { service: { entrypoint: 'astro/assets/services/sharp' } },
});
如果确实需要超过 8 GB,Pro 和 Enterprise 可以开 on-demand enhanced builds(8 CPU、16 GB 内存、58 GB 磁盘)。光把席位升到 Pro 并不会让 build 内存翻倍——必须主动把 enhanced builds 打开。
6. 输出目录 / 框架预设错
build 本身”成功”,但部署时报 No Output Directory named "public" found。Vercel 期望静态文件在 public,而你的框架写在别处——Astro 和 Vite 输出 dist,Next.js 输出 .next。这通常是框架预设设错,或某个手动的 Output Directory 覆盖项过时了。
在 Settings → Build and Deployment 修:把 Framework Preset 设成和你的技术栈匹配(Astro、Next.js、Vite…),并清掉任何手动的 Output Directory 覆盖(除非你真需要自定义)。让预设自己决定目录。
7. build 超时(45 分钟,每个套餐都一样)
Build Step 有 45 分钟硬上限,所有套餐都一样——Hobby 和 Pro 没区别。升级席位不会抬高它。在大型内容站上,你是靠一次性生成太多页面撞顶的。几个选择:
- 按语言或板块拆 build,作为多个独立项目部署。
- 每次 build 只生成最近 N 篇,其余的归档到单独部署里。
- 给 build 本身提速(更快的图片服务、减少冗余数据请求、在多次运行间复用缓存),让同样的页面数在 45 分钟内跑完。
// astro.config.mjs —— directory 输出,再限制每次 build 的页面数
export default defineConfig({
build: { format: 'directory' },
});
push 前先在本地复现失败
可复现的本地失败能把重新部署的循环从几分钟压缩到几秒。匹配 Vercel 的精确 build 路径:
npm ci # 严格按 lockfile 干净安装
npm run build # 和 Vercel 跑的同一条命令
想更贴近 Vercel 自己的容器环境,用 CLI:
vercel build --prod
vercel deploy --prebuilt --prod
容易踩的坑
- 只看 build 日志最底部。真实错误经常在最后那行 “exit code 1” 上面几行。
- 把环境变量加到了一个环境(Preview),却没加到真正失败的那个(Production)。
- 为”修”依赖错把
node_modules提交进仓库。这会撑大仓库、拖慢每次 build;刷新 lockfile 才对。 - 为绕一个类型错就全局关掉
strict。你把后面那十个错也一起藏起来了。 - 以为 Pro 会自动抬高 45 分钟超时或 8 GB build 内存。超时在每个套餐上都固定;内存提升需要主动开 enhanced builds。
FAQ
- 真正的错误到底在日志哪里?: 打开 deployment,展开 Building 步骤,找进程以非零码退出前最后一行红色。最底部的 “Command failed with exit code 1” 只是症状,真因通常在它上面一两行。
- 为什么本地能 build、Vercel 挂?: 三个常见差异——Node 版本不同(Vercel 默认 24.x)、某个 build 阶段的环境变量只存在你机器上、或某个文件路径的大小写在大小写不敏感的 macOS 上行、在大小写敏感的 Vercel Linux 上不行。
- 日志只写 “Killed” 是什么意思?: 内存不足。容器上限 8 GB。设
NODE_OPTIONS='--max-old-space-size=6144',降低并发和图片处理量,再不行才考虑 Pro 的 on-demand enhanced builds(16 GB)。 - 升级 Pro 能解决 build 超时吗?: 不能。45 分钟 build 上限在 Hobby 和 Pro 上完全一样。拆 build 或给它提速,升席位在这里帮不上忙。
- 能在本机跑 Vercel 的 build 容器吗?: 很接近,可以:
vercel build --prod再vercel deploy --prebuilt --prod,比单纯npm run build更贴近 Vercel 的 build 环境。