Skip to content

Debug Slow Indexing

import { Aside, Tabs, TabItem } from ‘@astrojs/starlight/components’;

A full forge index on a typical project (1K–50K files) takes 5–60 seconds. If indexing is taking several minutes or hanging, one of a few common causes is usually responsible.

Enable debug logging to see exactly where time is spent:

Terminal window
FORGE_LOG=debug forge index . 2>&1 | grep -E "timing|elapsed|ms\]"

Expected output:

[2026-04-16T14:32:01Z DEBUG forge::index] file discovery: 8432 files in 0.3s
[2026-04-16T14:32:01Z DEBUG forge::index] filter (ignored_paths): 2,891 files skipped in 0.1s
[2026-04-16T14:32:01Z DEBUG forge::index] parse phase: 5,541 files in 42.1s
[2026-04-16T14:32:43Z DEBUG forge::index] slowest files:
[2026-04-16T14:32:43Z DEBUG forge::index] dist/bundle.js (4.2MB) — 8.3s
[2026-04-16T14:32:43Z DEBUG forge::index] generated/api-types.ts (1.1MB) — 2.1s
[2026-04-16T14:32:43Z DEBUG forge::index] vendor/lodash.js (512KB) — 1.4s
[2026-04-16T14:32:43Z DEBUG forge::index] graph phase: 5,541 files in 2.8s
[2026-04-16T14:32:43Z DEBUG forge::index] search index: 5,541 files in 3.1s
[2026-04-16T14:32:43Z DEBUG forge::index] total: 48.4s

The slowest files list tells you exactly what to address.

Terminal window
forge stats

If Files indexed is much higher than you expect, files are being indexed that shouldn’t be:

Files indexed: 94,832 ← suspiciously high for a mid-size project

Run the full debug log and look for the file discovery count:

Terminal window
FORGE_LOG=debug forge index . 2>&1 | head -5

If the discovery count is high, node_modules, dist, or another large directory is being traversed.

The most common cause of slow indexing is large directories that should be excluded.

Add to .forge/config.toml:

[index]
ignored_paths = [
"node_modules",
"dist",
"build",
".next",
".turbo",
"coverage",
".cache",
"vendor",
"**/*.min.js",
"**/*.bundle.js",
"**/*.map",
]

Forge respects .gitignore by default — any file ignored by git is also ignored by Forge. If node_modules is in .gitignore, you don’t need to add it to ignored_paths explicitly. Check:

Terminal window
git check-ignore node_modules

If this prints node_modules, git is ignoring it and Forge will too.

If the directory is NOT in .gitignore but should be excluded from indexing, add it to ignored_paths.

Generated files — API type stubs, bundled JS, minified assets — are expensive to parse and rarely useful to index. Exclude them by pattern:

[index]
ignored_paths = [
"**/*.generated.ts",
"**/*.generated.js",
"src/generated/**",
"openapi/generated/**",
"graphql/generated/**",
]

For very large files that slip through, set a file size limit:

[index]
max_file_size_bytes = 524288 # 512 KB — skips large lock files and bundles

Forge’s default is 1 MB. Setting it to 512 KB filters most problem files while keeping all normal source files.

forge index is incremental by default — it only re-parses files that have changed since the last index. After the first full index, subsequent runs are usually under 5 seconds for repos with normal commit sizes.

When indexing seems slow on every run (not just the first), you’re hitting a full re-index each time. Causes:

  • The .forge/index/ directory is being deleted between runs (common in CI without caching)
  • A config change (ignored_paths, entry_points) triggers a rebuild
  • Using --full flag explicitly

To confirm the index is truly incremental:

Terminal window
FORGE_LOG=debug forge index . 2>&1 | grep -E "incremental|full index"

Output for incremental:

[DEBUG forge::index] mode: incremental (14 changed files since last index)

Output for full:

[DEBUG forge::index] mode: full (no existing index found)

If you see “full” on every run in CI, add index caching. See CI Cached Indexes.

forge serve . --watch runs a file watcher in addition to serving MCP. On repos with frequent file changes (active development with hot reload, generated files changing on save), the watcher can trigger many small incremental re-indexes.

If the watcher is adding noticeable overhead:

Terminal window
# Remove --watch to disable
forge serve .

Without --watch, the index is not updated while the server runs — it reflects the state when forge serve started. Restart the server to pick up new changes.

Indexing completes but feels slow in practice The index itself may be fine but searches are slow. Run:

Terminal window
FORGE_LOG=debug forge search "test query" 2>&1 | tail -3

If search latency is high, the search index may be large. Trim ignored_paths to reduce it, or increase max_results to check if it’s a result pagination issue.

forge index hangs indefinitely A file with unusual content (binary file misidentified as text, circular symlink in the directory tree) can cause the parser to stall. Kill the process, then run:

Terminal window
FORGE_LOG=trace forge index . 2>&1 | tail -20

The last few lines show which file it was processing when it stalled. Add that file or directory to ignored_paths.

Slow indexing only on CI (not local) CI runners typically have slower disk I/O than developer machines, and they start from a clean state with no index cache. See CI Cached Indexes to restore a cached index instead of re-indexing from scratch.