打开一个稍微大点的项目,Cursor 状态栏永远停在 Indexing 5% 半小时不动;或者跑完了又立刻重跑,整台机器风扇拉满。Cursor 并没有卡死。截至 2026 年 6 月,它默认就会遵守你的 .gitignore,外加一份内置默认忽略列表(node_modules/、lockfile、.env*、.git/、二进制文件),所以变慢的情况几乎总是某个默认列表没覆盖到、或被别的配置覆盖掉的目录:dev server 每次保存都重写的构建输出目录、某个缓存目录,或者 monorepo 某个子包的产物。文件监听器看到持续不断的变更,永远稳定不下来。
最快修复: 把那个吵闹的 build/缓存目录加进 .cursorignore,把同一路径加进 VS Code 的 files.watcherExclude,然后打开 Cursor Settings > Indexing 点 Resync Index。详细步骤和完整模板见下文。
先判断你属于哪一类
动手改之前,先把你的症状对到原因上。
| 症状 | 最可能的原因 | 跳转 |
|---|---|---|
Indexing 卡在低百分比,一直不动 | 在扫描一个巨大目录(vendored 依赖、生成代码、漏进来的 node_modules) | 原因 1 |
索引跑完后,只要 npm run dev 开着就每隔几秒重跑 | 构建产物 / 热重载写入反复触发监听器 | 原因 2 |
| 一停掉 dev server 死循环立刻停止 | 同上 | 原因 2 |
| 单仓库正常,只有 monorepo 出问题 | 子包产物(apps/web/.next、packages/ui/dist)叠加 | 原因 3 |
哪怕是个小仓库也一直 Setting up indexing... | 服务端或账号问题,不是你的文件 | 原因 4 |
| 开了 Privacy Mode 后一直转圈 | Privacy / 旧设置挡住了 embeddings 上传 | 原因 4 |
常见原因
1. 默认列表没覆盖到的大目录
Cursor 的内置列表已经会跳过 node_modules/,但 vendored 依赖(vendor/、third_party/)、生成的 SDK/protobuf、ML 权重(.pt、.safetensors),或者因为符号链接、奇怪的 workspace 根目录被重新算进来的 node_modules,都落在它之外。每一个都比你的源代码大两个数量级。
如何判断:数一数可疑目录里的文件。
# Cursor 可能要遍历的文件总数
find . -type f -not -path './.git/*' | wc -l
# 最常见的元凶
find node_modules -type f 2>/dev/null | wc -l
如果项目总数到了几十万,而 Cursor 一直停在 Indexing,就说明有目录需要忽略。健康的源代码树通常在 <= 30000 个文件以内。
2. 构建产物反复触发监听器(死循环)
这是现在最常见的一类。开了热重载后,dist/、.next/、.svelte-kit/、.turbo/ 每次保存都被重写。Cursor 收到变更事件就重新索引,形成 “索引完 -> 检测到变化 -> 重索引” 的死循环,把一个 CPU 核心占满。这里有两样东西都要忽略:索引(让文件不被重新 embedding)和文件监听器(让 Cursor 根本不被叫醒)。
如何判断:npm run dev 跑着的时候 Indexing 每隔几秒就冒出来一次,一停掉 dev server 就安静了。
3. Monorepo 子包产物
apps/web/.next、apps/api/dist、packages/ui/storybook-static 单看每个都不大,但加起来能到几百万文件。根目录一份 .cursorignore 里写裸的文件夹名(dist/)只匹配根目录;嵌套的副本需要用 glob。
如何判断:
find . -type d \( -name dist -o -name .next -o -name build -o -name .turbo \) -not -path '*/node_modules/*'
返回三条以上且没有 ignore 覆盖,就是它。
4. 服务端或 Privacy Mode(不是你的文件)
如果哪怕是个小仓库也一直显示 Setting up indexing...,那问题就不在文件上。代码库索引会把 embeddings 上传到 Cursor 的服务器;旧的 Privacy Mode 设置和偶发的后端故障都会挡住这一步。先看 Cursor 状态页,再检查 Cursor Settings > General > Privacy。语义搜索大约在完成度 80% 时才可用,所以卡在接近结尾的位置,也可能是服务端的 embedding 队列在排队,而不是本地扫描。
最短修复路径
Step 1:写一份”通杀”的 .cursorignore
在项目根创建或编辑 .cursorignore。它用 gitignore 语法,所以 ** 可以跨目录匹配。下面这些条目是在 Cursor 内置默认之外的补充(node_modules/ 其实不写也行,因为它本来就是默认项,但写上去意图更清楚,同时也把它从 @ 引用里硬挡掉):
# 依赖(默认已覆盖 node_modules,这里写出来表明意图)
node_modules/
vendor/
third_party/
# 构建产物(用 ** 在任意层级匹配,照顾 monorepo)
**/dist/
**/build/
**/out/
**/.next/
**/.astro/
**/.svelte-kit/
**/.nuxt/
**/.output/
**/storybook-static/
# 缓存
**/.cache/
**/.turbo/
**/.vercel/
**/.parcel-cache/
**/.pytest_cache/
**/__pycache__/
# 测试覆盖率与大文件
**/coverage/
**/.nyc_output/
*.safetensors
*.pt
# 日志
*.log
.cursorignore 会同时阻止文件被索引以及被 Agent、Tab、@ 引用访问。如果你只想把某个目录排除出索引、但仍然能在 @ 引用或拖进 chat 时被读到(遗留代码、大型 fixture),那就改放进 .cursorindexingignore,语法相同。注意 Cursor 把这一机制称为 best-effort:它并不绝对保证被忽略的文件永远不会被发给模型。
Step 2:别让文件监听器把 Cursor 叫醒
.cursorignore 能让文件不进索引,但 Cursor 底层的 VS Code 文件监听器仍然会在每次构建写入时触发,而这正是死循环不停的根源。把这些吵闹路径同样加进 Cursor Settings > settings.json 里的 files.watcherExclude(Cmd/Ctrl+Shift+P -> Preferences: Open User Settings (JSON)):
{
"files.watcherExclude": {
"**/node_modules/**": true,
"**/dist/**": true,
"**/.next/**": true,
"**/.turbo/**": true,
"**/.cache/**": true,
"**/coverage/**": true
}
}
在热重载项目上,真正终结重索引死循环的就是这一个设置。
Step 3:强制重建索引
改完 .cursorignore 不会自动重建。最快的办法是用命令面板(Cmd/Ctrl+Shift+P -> Reindex Codebase),或者从 UI 触发(这个菜单已经从旧的 “Features” 标签页改名了):
Cursor Settings > Indexing -> Resync Index
想连服务端状态一起清掉,就在同一面板上点 Delete Index,再点 Resync Index。对付特别顽固的死循环,最彻底的重置是退出 Cursor 后清掉本地 workspace 索引缓存:
# 先退出 Cursor,然后:
# macOS
rm -rf ~/Library/Application\ Support/Cursor/User/workspaceStorage/*/cursorIndex
# Linux
rm -rf ~/.config/Cursor/User/workspaceStorage/*/cursorIndex
# Windows (PowerShell)
Remove-Item -Recurse -Force "$env:APPDATA\Cursor\User\workspaceStorage\*\cursorIndex"
# 重新打开 Cursor
Step 4:把构建产物统一放进已忽略的目录
如果索引跑完了又被 dev server 触发重跑,确认你的工具链是把所有输出都写进已被忽略的目录,而不是散落在源代码旁边:
// vite.config.ts
export default {
build: {
outDir: 'dist', // 被 **/dist/ 匹配
},
cacheDir: '.cache/vite', // 被 **/.cache/ 匹配
}
如何确认真的修好了
- 重启 Cursor 重新打开项目,状态栏先短暂显示
Indexing 0%。 - 中型项目 1-3 分钟内到
Indexed;大型 monorepo 5-10 分钟。语义搜索约在 80% 时就开始可用,所以还没到 100% AI 就能用了别慌。 - 打开
Cursor Settings > Indexing & Docs > View included files(或看 Indexing 面板上的 “Files Indexed” 计数)。健康的中型项目大致在5000到30000个文件。还停在100000+ 说明有 ignore 规则没匹配上,回头检查你的 glob。 - 启动
npm run dev,盯着状态栏看一分钟。如果Indexing不再冒出来,说明 watcher exclude 生效了。
预防建议
- 创建仓库时就 commit
.cursorignore,并和.gitignore同步维护。 - build/缓存目录一律用
**/这样的 glob,才能连 monorepo 嵌套副本一起命中,而不只是根目录。 - 把这些吵闹路径一次性写进
files.watcherExclude,之后就不用再管了。 - 装新依赖、换构建工具、加代码生成器之后,主动点一次 Resync Index,别等死循环。
- 想让某个目录退出搜索、但仍能按需读取时,用
.cursorindexingignore(而不是.cursorignore)。
常见问题
Cursor 既然读 .gitignore,我还需要 .cursorignore 吗?
对 node_modules 和 lockfile 来说通常不用,因为它们在内置默认列表里。你需要它来处理那些没被 gitignore、但仍然很大或很吵的东西(vendored 代码、生成的 SDK、你提交进仓库的构建目录),以及把敏感文件从 Agent 那里硬挡掉。
.cursorignore 和 .cursorindexingignore 有什么区别?
.cursorignore 会把文件挡在索引以及所有 AI 访问之外(Tab、Agent、@ 引用)。.cursorindexingignore 只把它移出索引;你仍然可以 @ 引用它或拖进 chat。遗留代码和偶尔要引用的 fixture 用后者。
为什么我每次保存文件索引就重启?
你的 dev server 在重写一个仍然被监听的 build/缓存目录。把该路径同时加进 .cursorignore 和 files.watcherExclude(Step 2)。真正能停掉叫醒的是 watcherExclude 那一条。
哪怕小仓库也卡在 Setting up indexing...,怎么办?
这几乎都是服务端问题,不是你的文件。看 status.cursor.com,确认你已登录,再看 Cursor Settings > General > Privacy,因为旧的 Privacy Mode 设置会挡住 embeddings 上传。然后 Delete Index 再 Resync Index。
“Files Indexed” 应该显示多少?
一个典型应用大致在 5000 到 30000。如果你看到 100000+,说明有 ignore 规则没匹配上,通常是一个裸的 dist/ 没能命中 monorepo 的嵌套副本。换成 **/dist/。