Settings → Features → Codebase Indexing reads “Indexing… 3,432 of 1,200,000 files.” Half an hour later the count hasn’t moved; sometimes the spinner just turns at 0%. The most common cause isn’t a Cursor bug — it’s .cursorignore missing node_modules / build outputs, so a million generated files have been thrown into the scanner. After that: symlink loops, network mounts, permissions.
Fix by figuring out which class of files is stuck, then exclude precisely.
Common causes
1. node_modules / dist / .next / build not ignored
Cursor honors .gitignore by default, but lots of teams’ .gitignore lists node_modules and misses dist/, coverage/, .next/, .turbo/, __pycache__/, venv/. .next/cache/webpack alone can be 500k files in a Next.js monorepo.
How to judge:
git status --ignored | head -20
du -sh node_modules .next dist build coverage 2>/dev/null | sort -h
The biggest directory not in gitignore is the suspect.
2. Symlink loops
packages/web/node_modules/internal-pkg -> ../../shared, and shared symlinks back. Scanner recurses forever.
How to judge:
find . -type l 2>/dev/null | head -20
Any symlink pointing to a parent directory.
3. Repo exceeds Cursor’s default cap
Single-repo indexing roughly maxes out at 10k-500k files depending on plan. Beyond that, Cursor either gives up silently or retries forever. Real-LOC monorepos hit this fast.
How to judge:
git ls-files | wc -l # tracked
find . -type f | wc -l # all, including ignored
If the second number is >100k, you’re past scale.
4. Permission denied
A directory owned by root (system path, Docker volume) the Cursor process can’t read. The indexer hangs waiting.
How to judge:
find . -not -readable 2>/dev/null | head
5. Network drive / WSL boundary
Project on SMB / NFS / Dropbox / iCloud sync — file IO latency jumps to 100ms+, indexer throughput drops two orders of magnitude.
How to judge: df -h . for mount type; path like /mnt/c/... or ~/Library/Mobile Documents/....
6. Cursor’s indexer service hung
Extension host crashed or the index worker died, but the UI doesn’t update.
How to judge: Cmd+Shift+P → “Developer: Show Running Extensions” — Cursor’s index worker unresponsive.
Before you start
- Confirm whether it’s this one repo or every repo; the latter is usually a Cursor install or account problem.
- Commit
.cursorignorebefore editing so you can roll back. - Note Cursor version, repo file count, OS, subscription tier.
Info to collect
- Cursor version, plan (Hobby / Pro / Business).
- Output of
git ls-files | wc -landfind . -type f | wc -l. - Full
.cursorignore/.gitignore. - Screenshot of Settings → Features → Codebase Indexing.
- Help → Toggle Developer Tools → Console indexing-related logs.
Shortest fix path
Ordered by impact.
Step 1: Write a proper .cursorignore
At repo root, create / edit .cursorignore:
# Dependencies
node_modules
.pnpm
.yarn
vendor
__pycache__
venv
.venv
# Build output
dist
build
out
.next
.nuxt
.turbo
.svelte-kit
coverage
target
.gradle
# Caches
.cache
.parcel-cache
.eslintcache
*.tsbuildinfo
# Data files
*.parquet
*.bin
*.gz
*.zip
*.sqlite
# Logs
*.log
logs
# Lockfiles (optional — large but sometimes wanted)
# package-lock.json
# pnpm-lock.yaml
Step 2: Trigger a reindex
Cmd+Shift+P → “Cursor: Resync Index” (or “Rebuild Codebase Index”). Then Cmd+Shift+P → “Developer: Reload Window.” Watch progress for 5-30 minutes.
Step 3: Break symlink loops
find . -type l -exec ls -l {} \; 2>/dev/null | grep -E "\.\./.*\.\./"
For each parent-pointing symlink, either add it to .cursorignore or convert to a native npm / yarn workspace link.
Step 4: Narrow the working directory
Don’t open Cursor at a 50k-file monorepo root. File → Open Folder → pick the package you’re actually in this week (apps/web). Indexing surface shrinks by an order of magnitude.
Step 5: Move off network drive / WSL boundary
git clone to ~/repo (APFS, WSL ext4, native Linux). Don’t keep active projects in Dropbox / iCloud sync directories.
Step 6: Nuclear option — clear cache and rebuild
# macOS / Linux
rm -rf ~/Library/Application\ Support/Cursor/User/workspaceStorage/*
# Windows
# rmdir /s %APPDATA%\Cursor\User\workspaceStorage
This wipes every workspace’s index cache; every repo will reindex on next open. Use only as a last resort.
How to verify the fix
- Restart Cursor and reproduce — confirms it isn’t transient session state.
- Indexing progress reaches 100% in a reasonable time (≤ 30 minutes).
- Composer can answer “List every file under src/api/” with the real list, proving index coverage.
If it still fails
- Reduce repro: open a fresh empty repo, see if that also stalls.
- Roll back the most recent Cursor upgrade or
.cursorignorechange. - Search forum.cursor.com for “indexing never completes”; include file count + OS + ignore content.
- Grab Developer Tools → Console indexing logs and post to Bug Reports.
Prevention
- First thing on a new repo: drop in a
.cursorignore. Don’t wait to be bitten. - Keep
.cursorignoreand.gitignoredifferentiated: generated types / schemas the model needs stay in; node_modules always out. - Don’t commit datasets (parquet / sqlite / huge JSON) — use git-lfs or S3.
- Always run on native filesystems; never iCloud / Dropbox / network mounts.
- Quarterly
git ls-files | wc -l. Past 50k files, consider splitting the monorepo.