Large Codebases
Context strategies for repos too big to fit in a window — the prerequisite skill for any monorepo. See Working with Large Codebases.
Monorepo workflows with AI assistants rely on a project-graph MCP server, most commonly Nx Console, that hands Cursor, Claude Code, and Codex the dependency graph, generator schemas, and task cache as structured context. Paired with a rules file stating build order and layering constraints, impact analysis, cascade refactoring, and release ordering become queries rather than manual audits.
A security advisory drops for your auth library. It lives in @company/core, and 23 services across a 47-package monorepo import it. You need to know exactly which packages break, in what order they rebuild, and which teams to ping. Open the wrong file first and you spend the afternoon chasing transitive imports that a project graph could have answered in seconds. The same gap bites on a quiet Tuesday: rename a shared type and seven downstream packages break, two of them with integration tests that pass locally and fail in CI because a dependency was never rebuilt.
Out of the box, AI assistants treat your monorepo as a pile of files. They have no idea that web-app depends on @company/ui, which depends on @company/core. The fix is a project-graph MCP server (Nx Console is the most mature) that hands the model your dependency graph, generator schemas, and task cache as structured context. Once that’s wired up, “what breaks if I change this?” becomes a query, not a manual audit.
nx.json/turbo.json task graphs into concrete parallelization winsuvx missing, the MCP server failing to startThe Nx MCP server (nx-mcp) is the most capable monorepo integration today. It exposes your project graph, generator schemas, and Nx docs as tools the model can call. Setup is nearly identical across all three tools — the only real difference is the command you run.
Install the Nx Console extension. In an Nx workspace, Cursor (0.46+) auto-detects it and shows a notification offering to enable the Nx MCP server. Accept it, and Nx Console writes a .cursor/mcp.json entry for you.
To wire it up manually, run nx.configureMcpServer from the command palette (Cmd/Ctrl+Shift+P), or add the entry yourself:
{ "mcpServers": { "nx": { "command": "npx", "args": ["-y", "nx-mcp"] } }}Confirm it under Cursor Settings → MCP — you should see nx listed with a green dot.
Add it as a stdio server from the repo root. Use --scope project so the config is written to a shared .mcp.json rather than the default local scope (which lives in ~/.claude.json under your project path and is private to you). The --scope flag must come before the server name and the --:
claude mcp add nx --scope project -- npx -y nx-mcpVerify it registered and is reachable:
claude mcp listWith --scope project, the config lands in .mcp.json. Commit that file so the whole team gets the same graph-aware setup.
Register the same stdio server. Codex stores it in ~/.codex/config.toml:
codex mcp add nx -- npx -y nx-mcpcodex mcp listFor larger workspaces, give the server more startup headroom in ~/.codex/config.toml:
[mcp_servers.nx]command = "npx"args = ["-y", "nx-mcp"]startup_timeout_sec = 30Two more servers round out a monorepo setup. Note the launchers differ: the official filesystem server is a Node package run via npx, while the git server is Python-only and runs via uvx (install uv first). There is no @modelcontextprotocol/server-git on npm — that package does not exist.
{ "mcpServers": { "git": { "command": "uvx", "args": ["mcp-server-git", "--repository", "/path/to/monorepo"] }, "fs": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/monorepo"] } }}claude mcp add git -- uvx mcp-server-git --repository /path/to/monorepoclaude mcp add fs -- npx -y @modelcontextprotocol/server-filesystem /path/to/monorepocodex mcp add git -- uvx mcp-server-git --repository /path/to/monorepocodex mcp add fs -- npx -y @modelcontextprotocol/server-filesystem /path/to/monorepoScoping the filesystem server to the monorepo root keeps bulk operations inside your workspace and out of the rest of your disk.
The graph tells the model what depends on what. It does not tell the model what is allowed: that apps must never import from other apps, that core carries no external dependencies, that exports stay backward-compatible. That policy belongs in the rules file, and it is what stops a model from resolving a circular import by adding an edge you would reject in review. It is also the fallback when there is no graph server — a Turborepo workspace gets most of the benefit from the rules file alone.
Structure your .cursor/rules to encode the graph and the constraints together:
# .cursor/rules (root)This is a Turborepo monorepo managed with pnpm workspaces.
Package structure:- /packages/core - Shared types, utilities, base classes (NO external deps)- /packages/ui - React component library (depends on: core)- /packages/api-client - API SDK (depends on: core)- /apps/web - Next.js frontend (depends on: core, ui, api-client)- /apps/api - Express backend (depends on: core)- /apps/admin - Admin dashboard (depends on: core, ui, api-client)
Build order: core → ui, api-client → web, api, admin
CRITICAL RULES:- Changes to /packages/core affect ALL other packages. Always check downstream.- Never import from /apps/* into /packages/*- Shared types go in /packages/core/src/types/- Each package has its own tsconfig.json that extends /tsconfig.base.jsonWhen working on cross-package changes, explicitly reference the dependency chain:
@packages/core/src/types @packages/ui/src/components @apps/web/src/pages
Use the CLAUDE.md hierarchy so each package carries its own rules:
# /CLAUDE.md (root)pnpm monorepo with Turborepo. Run `pnpm turbo build` to build all packages.Run `pnpm turbo test` to test all packages.Package dependency graph: core → ui, api-client → web, api, admin.Always run `pnpm turbo build --affected` after cross-package changes.
# /packages/core/CLAUDE.mdFoundation package. Changes here cascade everywhere.After ANY modification: run `pnpm turbo build --filter='core...'`to rebuild every package that depends on core and verify compatibility.Exports must be backward-compatible. Use deprecation notices, not breaking changes.
# /packages/ui/CLAUDE.mdReact component library. Storybook for development: `pnpm storybook`.Components must be exported from /src/index.ts barrel.Every component needs a .stories.tsx and .test.tsx file.Sub-agents can then parallelize the per-package analysis without each one re-deriving the layout.
Codex reads AGENTS.md files before doing any work, so encode the monorepo workflow there (Codex does not read a file named codex.md unless you add it to project_doc_fallback_filenames):
Monorepo with Turborepo + pnpm workspaces.Before making cross-package changes:1. Run: pnpm turbo build --affected --dry-run to preview the affected chain2. Identify all packages in the dependency chain3. Make changes starting from the lowest dependency (core) upward4. Run tests after each package modification
After all changes: pnpm turbo build && pnpm turbo testUse separate git worktrees for parallel Codex tasks; ChatGPT desktop can create optional managed worktrees, while CLI/IDE tasks use worktrees you create or select.
The single highest-value monorepo move is asking the model what breaks before editing. With the Nx MCP active, the model calls nx_workspace and nx_project_details instead of guessing from import statements.
With real graph context, you get back something you can act on rather than a guess:
Useris imported by 8 packages. Addingstatusas optional is non-breaking at the type level. The packages that render user data and should be updated to show status:UserCard(web-app),UserProfile(mobile-app),UserList(admin-dashboard). Rebuild order:@company/core→@company/ui→ web-app, mobile-app, admin-dashboard.
That checklist is the difference between a controlled change and an afternoon of grep. The model read your actual graph, so the rebuild order and the “optional means non-breaking” call are grounded, not invented.
Once you trust impact analysis, the same graph awareness drives coordinated edits. Work from the bottom of the dependency tree upward, one layer at a time, so integration failures surface while the diff is still small. The workflow is identical across all three tools — the model proposes the plan, you approve it, then it executes package by package — so the difference is only in how you drive each tool. Cursor’s agent mode applies edits inline with checkpoints; Claude Code runs in the terminal and can chain into hooks or CI; Codex can fan work out to optional local worktrees in ChatGPT desktop or to separate hosted Cloud tasks.
Get the plan first. Run the impact prompt above so you have the affected-package checklist in dependency order, and review it against your own understanding before anything is edited.
Modify the source package and build it alone. Change the shared type, utility, or component in the foundational package and verify it compiles in isolation — pnpm turbo build --filter=core — before any dependent sees it.
Refactor one layer up at a time. Ask the model to work in dependency order so each package compiles before its dependents change:
Build and test each dependent before moving on. Do not climb another layer until the current one is green — that is what keeps a CI failure from arriving five packages later with no obvious cause.
Verify with the build graph. Run only what changed — npx nx affected -t build test lint, or pnpm turbo build --affected in a Turborepo workspace — and feed any failures back to the model with the package name and error.
Run the full pipeline once at the end. The affected-graph run is your fast loop; a complete build and test pass is what you trust before merging.
Without a graph server, the model cannot derive the order for itself — so you supply it. The prompt below is the same cascade written out by hand, which is what you reach for in a plain pnpm/Turborepo workspace, and its hard stop after the listing step is the safety the Nx version gets from the graph:
Impact analysis answers “what does this change touch?” A different question — “is this graph the shape we intended?” — needs its own pass, and it is the one that catches circular dependencies and layering violations before they calcify.
Analyze the import statements across our entire monorepo and build a dependency graph.Flag any:- Circular dependencies between packages- Apps importing from other apps (forbidden)- Packages importing from apps (forbidden)- Unused packages (no dependents)- Packages with suspiciously deep dependency chains (> 3 levels)
Visualize the graph as a text-based tree structure.claude "Analyze our monorepo's package dependency graph.Read every package.json in /packages/ and /apps/.Build the complete dependency graph and check for:1. Circular dependencies2. Violation of the layering rule (apps must not depend on other apps)3. Version mismatches for shared deps4. Packages that could be merged (similar purpose, small surface)Output the graph and any issues found."Perform a full dependency analysis of this monorepo.For each package, document:- Direct dependencies (internal)- Transitive dependencies (internal)- External dependency versions- Build time and test coverage
Create a dependency graph visualization in /docs/dependency-graph.md.Flag any architectural violations or optimization opportunities.Configuration drifts the same way the graph does, just more quietly: one package on a different TypeScript version, one missing the type-check script, one whose tsconfig.json stopped extending the base. Run this audit on a schedule rather than after something breaks.
Slow CI is usually a task-graph problem, not a hardware problem. The Nx MCP lets the model read your actual nx.json and project configs instead of giving generic advice.
A graph-aware model gives you specifics you can paste into a PR:
Your
web-app:builddeclares a dependency onmobile-app:build, but nothing in web-app imports mobile-app. Removing that edge lets the two apps build in parallel — roughly 40% off the critical path. Separately, yourtesttarget’sinputsinclude**/*.md, so doc edits bust the test cache. Narrow it to["default", "^default"].
For Turborepo, the same pattern applies to turbo.json — ask the model to audit inputs, outputs, and dependsOn — but you’ll feed it the file contents directly rather than through an MCP tool until an official server ships.
Multi-package releases are where dependency order bites hardest: ship @company/payments before the @company/core it depends on and you publish a broken version. Pair the git MCP (commit history) with the Nx MCP (dependency order) for this.
That prompt plans a release from history. The next one executes one for a change you just finished: it works from the packages you touched rather than from the tag, and it ends in the actual bump commands in the right order.
Graph-aware tooling fails in a handful of predictable ways. Recognize them fast:
claude mcp list (or codex mcp list) — a server stuck in “failed” usually means the launcher binary is missing. For nx-mcp and the filesystem server you need Node/npx on PATH; for the git server you need uv/uvx. Install uv if uvx is “command not found”.@modelcontextprotocol/server-git and got a 404. That package isn’t on npm — the git server is Python-only. Use uvx mcp-server-git --repository /path instead.nx.json lives. If the model says “no Nx workspace detected”, restart it from the repo root.npx nx reset to clear the Nx cache, then ask the model to re-read the graph before trusting a new impact report..cursor/rules / CLAUDE.md / AGENTS.md — the graph server supplies the edges, the rules file supplies the obligation.turbo build --affected (or --filter=...[origin/main]) rather than the single package you edited.nx affected --base=main), and bump startup_timeout_sec for the server if it’s timing out on first call.Monorepo migrations are slow and parallelizable, which makes them a fit for Codex’s multi-surface model. In ChatGPT desktop, a local task can use an optional managed git worktree; a Codex Cloud task instead runs in a separate hosted environment. Use one isolated task per package group, then apply Cloud results locally:
# Browse or run cloud tasks from the terminalcodex cloud
# Apply a completed cloud task's diff to your local treecodex applyThis lets you fan a “migrate package group A to the new API” task out to the cloud while you keep editing locally, then review each diff with codex apply before it lands.
Large Codebases
Context strategies for repos too big to fit in a window — the prerequisite skill for any monorepo. See Working with Large Codebases.
Microservices
Coordinate changes across service boundaries with the same graph-first mindset. See Microservices Workflows.
Code Quality at Scale
Keep linting, types, and tests consistent across every package. See Code Quality Workflows.
CI/CD Pipelines
Build and deploy monorepo packages with AI-optimized pipelines. See Pipeline Automation with AI.
MCP Ecosystem
Go deeper on configuring and combining MCP servers across all three tools. See the MCP Ecosystem guides.