Skip to content

Configure Forge for a Monorepo

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

Monorepos work with Forge out of the box — run forge index at the repo root and Forge indexes everything. The challenge is tuning configuration so Forge understands which packages are entry points, which paths to ignore, and how packages relate to each other.

Run forge index from the monorepo root:

Terminal window
forge index /path/to/monorepo --with-search --with-git

Forge walks the entire directory tree, parsing all supported source files. For a typical monorepo with 50–200 packages, initial indexing takes 30–120 seconds. Subsequent incremental runs are much faster.

Verify the index:

Terminal window
forge stats

Expected output:

forge stats: /home/you/repos/monorepo
Files indexed: 8,432
Symbols extracted: 94,217
Packages found: 47
Languages: TypeScript (6,201), JavaScript (1,891), Python (340)
Index size: 187 MB
Last indexed: 2026-04-16 14:32:01 (2 minutes ago)

Create .forge/config.toml in the monorepo root:

[index]
# Paths to skip during indexing
ignored_paths = [
"node_modules",
"dist",
"build",
".next",
".turbo",
"coverage",
"**/*.test.ts",
"**/*.spec.ts",
]
# Entry points for reachability analysis (forge_check_wiring)
# These are the roots of the dependency graph
entry_points = [
"apps/web/src/index.ts",
"apps/api/src/main.ts",
"apps/mobile/index.js",
]
[search]
# Max results per search query
max_results = 50
[health]
# Minimum coverage threshold for P2 warning (0 = disabled)
min_coverage = 0

After creating or editing .forge/config.toml, re-run forge index to apply the new configuration.

Forge recognizes workspace configurations automatically.

If package.json at the root defines a workspaces field, Forge uses it to identify package boundaries:

{
"workspaces": [
"packages/*",
"apps/*"
]
}

Forge maps cross-package imports correctly — an import from @myorg/ui in apps/web resolves to packages/ui/src/index.ts, not an unresolved external.

Forge reads Cargo.toml at the repo root to identify workspace members:

[workspace]
members = [
"crates/core",
"crates/cli",
"crates/server",
]

Cross-crate imports resolve within the workspace.

For Python monorepos using namespace packages or PEP 517 workspace tooling (Poetry workspaces, uv), add package roots to the config explicitly:

[index]
entry_points = [
"services/api/main.py",
"services/worker/main.py",
"libs/core/__init__.py",
]

Forge follows relative imports and sys.path-style references within the indexed tree.

If your monorepo uses TypeScript path aliases (e.g., @app/*, ~/*), Forge reads them from tsconfig.json automatically. For non-standard alias resolution, specify them in .forge/config.toml:

[resolve]
aliases = [
{ alias = "@app", target = "apps/web/src" },
{ alias = "@shared", target = "packages/shared/src" },
{ alias = "~", target = "src" },
]

Without this, imports using these aliases appear as unresolved and generate P0 broken_import findings.

After indexing, verify that cross-package imports resolve correctly:

Terminal window
forge health

Look for broken_import findings. If you see many errors like:

P0 broken_import: apps/web/src/components/Button.tsx:3
cannot resolve '@shared/ui'

This means path aliases or workspace config isn’t set up. Add the alias to .forge/config.toml and re-index.

You can also check a specific package’s wiring:

Terminal window
forge check-wiring apps/web/src/index.ts

Expected output when correctly configured:

forge check-wiring: apps/web/src/index.ts
Reachable from entry points: YES
Entry point: apps/web/src/index.ts (self)
Path: (entry)
Outbound imports: 14 files
All imports resolved: YES

For monorepos with 500K+ files (large company repos), tune the ignored paths aggressively:

[index]
ignored_paths = [
"node_modules",
"dist",
"build",
".cache",
".turbo",
"storybook-static",
"**/*.min.js",
"**/*.bundle.js",
"**/__mocks__",
"vendor",
"third_party",
]
[index]
# Limit file size (bytes) — skips generated files and large JSON
max_file_size_bytes = 512000

Duplicate symbol warnings after indexing If the same package appears multiple times (e.g., packages/ui and node_modules/packages/ui), add the duplicate path to ignored_paths. node_modules is ignored by default; if you see duplicates, a symlink or unusual path is creating a second traversal.

Entry points show as “unreachable” forge_check_wiring returns “unreachable” only when a file has no path from any declared entry point. If the file IS an entry point, add it to entry_points in .forge/config.toml.

Indexing takes over 5 minutes Check forge stats for file count. If it’s unexpectedly high (>100K files), a large directory is being indexed that shouldn’t be. Run FORGE_LOG=debug forge index . to see which paths are taking the most time, then add them to ignored_paths.