I work in three codebases regularly. One is a small Next.js app (15k lines, single package). One is a medium-sized Go service (60k lines, single package). One is a 1M-line monorepo (14 packages, multiple languages, accumulated over years).
The AI tooling experience differs across these in ways that aren’t well-documented. Specifically: the monorepo gets a worse experience from every AI tool I’ve tried. The reasons are interesting and the workarounds are real but partial.
Where the monorepo tax shows up
Indexing. Cursor’s codebase indexing on the monorepo takes 30 minutes the first time, 5-10 minutes after that. On the small app, it’s 30 seconds. The model has more to learn on the monorepo, but the effect on user experience is real — you wait, then you work.
Search relevance. When I ask “where is X used,” the monorepo returns 50 results, of which the relevant ones might be in positions 12-15. The small app returns 3 results, all relevant. The model uses what’s high in the rankings; on the monorepo, that’s often wrong.
Auto-context loading. Cline’s repo map auto-loads relevant files. On the monorepo, “relevant” is fuzzy — too broad and you load 200k tokens, too narrow and you miss important context. On the small app, the right files are obvious.
Cross-package consistency. The monorepo has 14 packages with subtly different conventions (legacy code, evolving patterns). The model defaults to whichever pattern is most common in its training, which often doesn’t match the package I’m working in.
Build feedback. On the small app, “did the change break anything?” is answered in 8 seconds (npm test). On the monorepo, the equivalent answer takes 15 minutes (the test suite is larger). This affects the agent loop — Cline can’t iterate quickly when each iteration takes 15 minutes.
Why this is structural, not solvable
Some of these are tooling problems with potential solutions. Some are fundamental.
The fundamental ones:
Larger codebases have more context to manage. No matter how good the indexing or retrieval, a 1M-line codebase has more to filter through than a 15k-line codebase. The probability of finding the wrong context is higher. The probability of missing important context is also higher.
More inconsistency means more conflicting signals. A monorepo accumulates patterns over time. Five different ways to handle errors. Three different testing approaches. Two state management libraries. The AI sees all of them and can’t tell which is the current standard.
More history means more deprecated code. Old code that still exists but shouldn’t be used. The model treats it as live code and learns from it. The newer engineer who knows “we don’t write that anymore” has knowledge the model doesn’t.
These aren’t going away. They’re properties of working in a large codebase.
The tooling problems that are solvable
Some of the tax is implementation-level:
Better workspace awareness. Tools that read package.json workspaces, Cargo.toml workspace, etc., can scope work to the active package automatically. Cursor’s indexing doesn’t do this well. Cline’s defaults are similarly broad.
Per-package context profiles. A .cursor/rules/<package>.mdc file (Cursor’s pattern) lets you specify “when working in this package, use these conventions.” The infrastructure exists; using it well is on the user.
Better generated-code awareness. Generated files, build outputs, and vendored dependencies should be excluded from indexing by default. Each tool requires manual .cursorignore or equivalent.
Smarter file selection for autonomous loops. Cline’s autonomous mode shouldn’t pull files from unrelated packages by default. The “subtree-only” mode helps but isn’t the default behavior.
These are improving over time. They’re not why the monorepo experience is worse; they’re why it’s worse than it could be.
Workarounds that actually work
For monorepo work, the patterns that have helped me most:
Open the monorepo at the package level. Run cd packages/active-package && cursor . instead of cursor /path/to/monorepo. The tools treat the package as the project root. Cross-package work becomes harder, but most work is single-package.
Per-package rules files. I keep .cursor/rules/ files (or .clinerules per package) that codify each package’s conventions. The model loads only the relevant rules when I’m in that package.
Aggressive .cursorignore. Generated code, build outputs, vendored deps, snapshot tests — all excluded from indexing. The remaining indexed area is closer to “code humans write.”
Pinned context in chat sessions. When I open a chat, I pin the 3-5 files that are relevant to my current task. The model uses those; the broader index is fallback for things not pinned.
Smaller test scopes. Configuring AI agents to run only the tests for the package I’m in, not the whole monorepo. The feedback loop matches the small-app experience.
Combined, these recover maybe 70% of the small-app experience for monorepo work. The remaining 30% is the structural tax — the inherent cost of more code, more history, more inconsistency.
What this means for tool choice
For monorepo work specifically, my preferences:
Cursor is the most usable on monorepos because of its codebase indexing and pinning support. The performance is mediocre but the workflow tools (per-directory rules, multi-file editing) help.
Cline is workable with careful configuration. The agentic style needs more constraint on monorepos to avoid going off in unrelated directions. Plan mode helps; explicit .clinerules are essential.
Aider is better in subtree mode than in full-repo mode. For monorepos where most work is one-package-at-a-time, subtree-only is the default I’d recommend.
Windsurf I haven’t used as heavily on monorepos. Cascade’s behavior on large codebases varies; I’d evaluate before committing.
For small-app work, the differences between tools matter less because the structural tax isn’t there. Pick based on workflow fit, not codebase size handling.
What tool vendors should do
The features I’d most want:
First-class monorepo awareness. Read package boundaries from the project’s manifest files. Treat each package as a context unit. Cross-package work is opt-in, not default.
Per-package model behavior. Different packages may benefit from different model defaults (different instruction sets, different tool selections). Tools should support this.
Better generated-code detection. Heuristics for identifying generated files (file headers, build artifacts, content patterns) that don’t require manual ignore configuration.
Agent-mode constraints for large repos. Autonomous agents should know they’re in a large repo and apply more conservative file expansion. The “expand context aggressively” pattern that works on small repos fails on monorepos.
These are specific, achievable improvements. Whether the tools prioritize them depends on whether monorepo users are vocal enough to influence the roadmap.
The honest assessment
For now, the monorepo tax is real. AI tools work but with friction that small-repo users don’t experience. If you’re in a small repo, your AI experience is better than the marketing promises. If you’re in a monorepo, your experience is worse than the marketing implies.
This isn’t unique to AI. Most developer tools work better on small projects. Build systems, IDEs, type checkers — all of them get more sluggish and more error-prone on large codebases. AI tools are continuing the pattern.
For monorepo workers: keep your expectations calibrated, configure aggressively, and don’t blame yourself when the AI gets confused. Some of the difficulty is real, regardless of what you do.