Tinker AI
Read reviews
advanced 8 min read

Aider in a monorepo: scoping context to one package without losing the cross-package picture

Published 2026-04-21 by Owner

Aider was designed around single repos. Run it in a monorepo with 12 packages and 800k lines of code, and the default behavior is painful: the repo map tries to summarize everything, the auto-commit logic fights with the workspace structure, and your token bill triples because the model keeps loading shared types from packages you’re not editing.

I’ve been running aider on a Turborepo monorepo for the past four months. Here’s the working setup.

The structure

For context, the repo:

packages/
  ui/           # shared component library
  api-types/    # generated TypeScript types from OpenAPI
  utils/        # shared utilities
apps/
  web/          # Next.js app
  admin/        # internal admin panel
  worker/       # background job processor

The classic problem: you’re editing apps/web and need to import a type from packages/api-types. Aider needs to see the type to generate correct code, but doesn’t need to load every other shared package.

Step 1: subtree scoping

Run aider from within the package you’re editing:

cd apps/web
aider --subtree-only

The --subtree-only flag tells aider to treat apps/web as the project root for the repo map. Files outside this directory aren’t auto-included. Git operations still work against the parent repo, which is what you want — commits land in the monorepo’s main branch.

This alone reduces the repo map from “all 12 packages” to “just apps/web.” Token usage drops by roughly 60% on a typical session, and aider stops suggesting changes to unrelated packages.

Step 2: explicit imports for cross-package types

When you need types from packages/api-types, add them via the /add command with the relative path:

> /add ../../packages/api-types/src/users.ts
> /add ../../packages/api-types/src/orders.ts

Aider supports paths outside the subtree when added explicitly. The model now sees the type definitions without loading the entire api-types package.

The pattern: subtree scope by default, explicit add for cross-package files you actually need. This forces you to think about what types you need, which is a feature, not a bug.

Step 3: a .aiderignore that knows about the workspace

At the monorepo root, create .aiderignore:

# Build outputs
**/dist/
**/.next/
**/build/
**/.turbo/

# Generated files
packages/api-types/src/generated/
**/*.generated.ts

# Lockfiles
**/pnpm-lock.yaml
**/package-lock.json
**/yarn.lock

# Test outputs
**/coverage/
**/playwright-report/

# Dependency graphs
**/node_modules/

The two lines that matter most for monorepos: ignoring **/dist/ (so you don’t get auto-completion suggesting symbols from compiled output) and ignoring generated files like packages/api-types/src/generated/. Generated files often have idiomatic patterns that the model picks up and applies to your hand-written code, which is wrong.

.aiderignore works at any directory level, but putting it at the monorepo root means it applies regardless of which package you’re working in.

Step 4: package-specific .aider.conf.yml

Each package can have its own .aider.conf.yml for package-specific settings:

# apps/web/.aider.conf.yml
model: claude-3-5-sonnet-20241022
edit-format: diff
auto-commits: false
read:
  - tsconfig.json
  - next.config.mjs
  - tailwind.config.ts

The read field is the lever. These files load on aider start, and they’re exactly the configuration the model needs to suggest changes that match your stack — TypeScript paths, Next.js routing rules, Tailwind class names. Without these in context, the model defaults to whatever pattern was popular in its training data.

For apps/admin, you might use a different read set; for apps/worker, you don’t need Tailwind config. Each package loads only what it needs.

What this fixes in practice

A real example from my codebase. I wanted to add a new API route in apps/web that calls a service in packages/utils and returns a typed response defined in packages/api-types.

Before this setup:

  • aider loaded the whole monorepo’s repo map (140k tokens)
  • Generated code referenced apps/admin-style patterns even though I was in apps/web (wrong middleware)
  • Auto-commits kept committing to the parent repo with messages mentioning unrelated packages
  • Total cost for the task: $4.20

After:

  • Repo map scoped to apps/web only (28k tokens)
  • I added the two relevant cross-package files explicitly with /add
  • Code matched apps/web conventions
  • Total cost: $1.10

The cost reduction was nice. The reduction in wrong-pattern suggestions was more valuable.

What still doesn’t work great

Refactors that span multiple packages. If you need to rename a function in packages/utils and update all callers, subtree scoping makes this harder. For these tasks, run aider from the monorepo root without --subtree-only, but be prepared to spend more on tokens.

Turborepo task awareness. Aider doesn’t know about your turbo.json task graph. If your change requires a build in a dependent package before the typecheck passes, aider won’t run the build. You handle that yourself.

Workspace dependencies. When apps/web imports from @org/utils (a workspace dependency), aider sees the import but doesn’t always resolve it correctly to packages/utils/src/index.ts. Adding packages/utils/src/index.ts to the read list of your package config fixes this for the most-used cases.

Worth it?

For a monorepo with more than three packages and active cross-package work, yes. The setup takes 30 minutes. The payoff is aider that produces relevant suggestions at a fraction of the token cost.

For a monorepo where everyone works in one or two packages and rarely touches others, the default --subtree-only is probably enough. You don’t need the full pattern.