Skip to content
Canopy is in pre-release. These docs describe the product at its public launch — commands, tool names, and integration examples reflect what you'll see once binaries ship. Join the waitlist →

Configure Canopy for a Monorepo

Monorepos work with Canopy out of the box — run canopy index at the repo root and Canopy indexes everything. The challenge is tuning configuration so Canopy skips the right paths and resolves cross-package imports correctly.

Run canopy index from the monorepo root:

Terminal window
canopy index /path/to/monorepo

Canopy walks the entire directory tree, parsing all supported source files. Full-text search and vector embeddings are built by default, and git commit history is ingested automatically when a .git/ directory is present. 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
canopy doctor

Expected output (excerpt):

Canopy v2.0.0-alpha.1
binary: /usr/local/bin/canopy
data dir: /home/you/.canopy
License
Solo
Index
status: indexed
database: /home/you/.canopy/7c4d2f8a91b4e6d2/forge.db
Summary backend (would-activate)
backend: heuristic
data flow: nothing leaves the box

Create .canopyignore in the monorepo root (gitignore syntax):

node_modules
dist
build
.next
.turbo
coverage
**/*.test.ts
**/*.spec.ts

Canopy already honors .gitignore and a bundled default ignore set; use .canopyignore for paths that should be excluded from the index but not from git. Two more layers compose with it:

# <repo>/.canopy/config.toml — per-repo config
[indexer]
extra_ignore_patterns = ["**/*.generated.ts", "openapi/generated/**"]
# <repo>/.canopy/team.yml — shared, checked into the repo
ignored_paths:
- vendor/
- generated/

After changing ignore rules, re-run canopy index to apply them. Preview the effect first with canopy index . --list-ignored, which prints what would be indexed vs skipped without indexing.

Canopy recognizes workspace configurations automatically.

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

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

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

If your monorepo uses TypeScript path aliases (e.g., @app/*, ~/*), Canopy reads them from compilerOptions.paths and baseUrl in tsconfig.json (or jsconfig.json) automatically, alongside workspace package-name aliases from package.json. Aliases that can’t be resolved appear as unresolved imports and generate broken_imports findings.

After indexing, verify that cross-package imports resolve correctly. On Pro tier, run the health check in CI mode:

Terminal window
canopy ci --format json

Look for broken_imports findings:

{
"check_id": "broken_imports",
"detail": "Import specifier '@shared/ui' in 'apps/web/src/components/Button.tsx' line 3 could not be resolved to any indexed file. Check that the target file exists and its extension is indexable.",
"file_path": "apps/web/src/components/Button.tsx",
"line_number": 3,
"message": "Unresolved import '@shared/ui'",
"severity": "warning"
}

A cluster of broken_imports findings on one alias means the path alias or workspace config isn’t set up. Fix the tsconfig.json paths (or the workspace definition) and re-index. On Solo tier, the same findings appear in the local dashboard (canopy dashboard).

You can also check a specific package’s wiring by asking the answer engine:

Terminal window
canopy answer "is \`apps/web/src/index.ts\` reachable?"

The same question works through the canopy_answer MCP tool from your editor. The response names the reachability path from an entry point; an unreachable file gets an explicit unreachable verdict.

For monorepos with 500K+ files (large company repos), tune .canopyignore aggressively:

node_modules
dist
build
.cache
.turbo
storybook-static
**/*.min.js
**/*.bundle.js
**/__mocks__
vendor
third_party

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 .canopyignore. node_modules is ignored by default; if you see duplicates, a symlink or unusual path is creating a second traversal.

Indexing takes over 5 minutes Check canopy index . --list-ignored for the would index count. If it’s unexpectedly high (>100K files), a large directory is being indexed that shouldn’t be. Run canopy index . --log-level debug to see which paths are taking the most time, then add them to .canopyignore.