Vercel deployment 列表里那条红色 “Build Failed” 不可怕,可怕的是滚动几千行 log 抓不到真正的报错。Vercel 的 build log 输出是按时间顺序的混合流——install 阶段的 npm warning、TypeScript 的 info、framework 自己的进度条全堆在一起,真正的错误往往被一堆绿色 info 行淹没。这篇教你 30 秒定位 log 里的关键位置,并按 5 类最常见失败模式给出对应修复——覆盖 Next.js、Astro、Vite、Remix 等所有主流框架的 Vercel 部署。
常见原因
按命中率从高到低:
1. Node / 依赖版本本地和 Vercel 不一致
最高频。本地 node -v 是 v20.10,Vercel 默认用最新 LTS 也可能切到 v22;某些 npm 包(sharp、canvas、bcrypt 这类有 native binding 的)在新版 Node 上 ABI 不兼容直接编译失败。
error gyp ERR! build error
node-pre-gyp ERR! Tried to download(404): https://...
如何判断:log 最顶部会显示 Running "install" command: npm install 和当前 Node 版本,对照本地 node -v。差超过一个 major 就是这问题。
2. 生产 env vars 缺失或拼写错
build 阶段需要的 env var(比如 NEXT_PUBLIC_SUPABASE_URL、SANITY_PROJECT_ID)只配在 Preview scope,没勾 Production;或者 dashboard 里写成了 SUPABSE_URL(拼错)。
Error: Environment variable NEXT_PUBLIC_SUPABASE_URL is not set
at Object.<anonymous> (/vercel/path0/lib/supabase.ts:4:5)
如何判断:log 里搜 is not set / undefined + 你认识的 env var 名字。
3. OOM——build 超内存(exit 137)
大型 Next.js 项目、千页静态生成、或 TypeScript 项目类型计算太重,build 内存超过 default 8GB(Hobby)/ 9GB(Pro)被 kernel 杀掉。
<--- Last few GCs --->
<--- JS stacktrace --->
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
Error: command "npm run build" exited with 137
如何判断:log 末尾出现 exited with 137 或 heap out of memory。
4. TypeScript strict 模式 / lint 错误本地被跳过
next build / astro build 默认会跑 tsc --noEmit,CI 上严格执行;本地用 npm run dev 时跳过类型检查所以没暴露。
Type error: Property 'user' does not exist on type 'Session | null'.
47 | export default function Page({ session }) {
48 | return <div>{session.user.name}</div>
^
如何判断:log 里有 Type error: / error TS\d{4} / ESLint error,能定位到具体文件行号。
5. Monorepo 的 Root Directory 配错
仓库根目录是 monorepo(pnpm workspace / Turborepo),Vercel 项目设置里 Root Directory 留空或指错了子目录,build 找不到 package.json 或拿到错误的依赖。
Error: No Next.js version detected. Make sure your package.json has "next" in either "dependencies" or "devDependencies".
如何判断:log 第一行 Cloning ... 之后那条 Running "install" 看 cwd 是不是你期望的子项目路径。
6. 文件大小写在 macOS vs Linux 不一致
macOS 默认大小写不敏感(Header.tsx vs header.tsx 等价),Linux build 严格。本地 import './header' 但文件叫 Header.tsx,本地过,Vercel 报 module not found。
Module not found: Can't resolve './header' in '/vercel/path0/components'
如何判断:错误信息 Can't resolve './xxx',但你本地确认文件存在——99% 是大小写不一致。
log 里要看的三个位置
不管是哪类失败,先扫这三处:
- 最末尾的 stack trace——日志最底下那段红色,通常 Node 抛的错,前两行就是真因
error高亮行——Vercel 把error:/Error:自动染红,用浏览器 Find 搜error跳过去- exit code——log 倒数第 1-2 行的
Error: command "..." exited with N:137= OOM,134= abort,1= generic,2= misuse
最短修复路径
Step 1:本地复现 Vercel 的 build 环境
# 锁死 Node 版本
nvm use 20 # 或 Vercel dashboard 里显示的版本
# 清掉缓存彻底重 build
rm -rf node_modules .next dist
npm ci # 严格按 lockfile,等价于 Vercel 的 install
npm run build
90% 的情况本地这一步就能复现。在 package.json 加 engines 锁死:
{
"engines": {
"node": "20.x",
"npm": ">=10"
}
}
Step 2:按错误类别对症下药
| log 关键词 | 真因 | 修复 |
|---|---|---|
exited with 137 / heap out of memory | OOM | 加 NODE_OPTIONS=--max-old-space-size=8192 |
is not set / undefined + env name | env var | dashboard 里勾 Production scope |
Type error: / error TS\d{4} | TS strict | 本地 tsc --noEmit 全跑一遍再 push |
Can't resolve | 大小写不一致 | 把 import 改成精确文件名 |
gyp ERR! / node-pre-gyp | native module + Node 不兼容 | 锁 Node 版本,或换无 native binding 的等价包 |
No Next.js version detected | monorepo Root Directory 错 | dashboard → Settings → General → Root Directory |
Step 3:内存问题加 NODE_OPTIONS
Vercel dashboard → Settings → Environment Variables → 加一条:
Key: NODE_OPTIONS
Value: --max-old-space-size=8192
Scope: Production + Preview
或在 package.json script 里写死:
{
"scripts": {
"build": "NODE_OPTIONS='--max-old-space-size=8192' next build"
}
}
Step 4:用 vercel logs / vercel —debug 拿完整 log
UI 上 log 有截断和滚动卡顿,CLI 看全文更方便:
# 拉最近一次 build log
vercel logs <deployment-url>
# 触发一次 debug build 看每一步的耗时
vercel --debug
Step 5:点 Redeploy 而不是 push 新 commit
试好修复方案后,先在 dashboard 点 Redeploy(不勾 “Use existing Build Cache”)测试,比 push 新 commit 快 1-2 分钟,也避免污染 git 历史。
确认成功再 commit 永久修复。
预防建议
package.json必加engines.node,跟 Vercel dashboard 选的版本对齐- 本地用
nvm use+npm ci严格复现 CI 环境,不用npm install - 新加 env var 时立刻同步到 Production / Preview / Development 三个 scope
- CI 里跑
tsc --noEmit+eslint+next build,本地 pre-push hook 也跑 - Linux container(Docker / GitHub Actions)跑一次 build,比 macOS 更接近 Vercel 的 Linux 环境
- 文件命名约定写到
CONTRIBUTING.md:组件首字母大写,路由小写,import 严格匹配