Complex Project Architecture with AI

Monorepo Patterns with AI Assistance

5 min read

Why Monorepos for AI-Assisted Development?

Monorepos provide AI assistants with crucial advantages:

  1. Complete Context: AI can see all packages and their relationships
  2. Consistent Patterns: Shared configs mean consistent code style
  3. Type Safety: Shared types across packages
  4. Atomic Changes: Modify multiple packages in one commit

Monorepo Structure for AI

Optimal Directory Layout

my-monorepo/
├── apps/
│   ├── web/                 # Next.js frontend
│   ├── api/                 # Node.js backend
│   └── admin/               # Admin dashboard
├── packages/
│   ├── ui/                  # Shared React components
│   ├── database/            # Prisma schema & client
│   ├── types/               # Shared TypeScript types
│   ├── utils/               # Shared utilities
│   └── config/              # Shared configs (ESLint, TS)
├── turbo.json
├── package.json
└── .claude/
    └── context.md           # AI context documentation

AI Context File

Create a context file that helps AI understand your monorepo:

<!-- .claude/context.md -->

# Monorepo Context

## Package Relationships
- `apps/web` depends on: `packages/ui`, `packages/types`, `packages/utils`
- `apps/api` depends on: `packages/database`, `packages/types`, `packages/utils`
- `packages/ui` depends on: `packages/types`
- `packages/database` depends on: `packages/types`

## Development Commands
- `pnpm dev` - Start all apps
- `pnpm build` - Build all packages
- `pnpm test` - Run all tests
- `turbo run build --filter=web` - Build specific app

## Adding New Components
1. Shared components go in `packages/ui`
2. App-specific components go in `apps/[app]/components`
3. All components must export from index.ts

## Type Conventions
- API response types in `packages/types/api.ts`
- Database models in `packages/types/models.ts`
- Shared utilities in `packages/types/utils.ts`

AI-Assisted Package Creation

Creating a New Shared Package

claude "Create a new shared package 'packages/email' for
sending transactional emails. Include:
1. Package setup with proper tsconfig
2. Email service abstraction
3. SendGrid and Resend providers
4. Type definitions
5. Export configuration"

Claude Code generates the complete package:

// packages/email/src/index.ts
export { EmailService } from './service';
export { SendGridProvider } from './providers/sendgrid';
export { ResendProvider } from './providers/resend';
export type { EmailProvider, EmailOptions, EmailResult } from './types';
// packages/email/src/types.ts
export interface EmailOptions {
  to: string | string[];
  subject: string;
  html: string;
  text?: string;
  from?: string;
  replyTo?: string;
}

export interface EmailResult {
  success: boolean;
  messageId?: string;
  error?: string;
}

export interface EmailProvider {
  send(options: EmailOptions): Promise<EmailResult>;
}
// packages/email/src/service.ts
import type { EmailProvider, EmailOptions, EmailResult } from './types';

export class EmailService {
  constructor(private provider: EmailProvider) {}

  async send(options: EmailOptions): Promise<EmailResult> {
    return this.provider.send(options);
  }

  async sendBatch(emails: EmailOptions[]): Promise<EmailResult[]> {
    return Promise.all(emails.map((email) => this.send(email)));
  }
}

Wiring Up Dependencies

claude "Add the email package as a dependency to apps/api.
Update the dependency graph in turbo.json if needed."

Cross-Package Refactoring

Scenario: Renaming a Shared Type

claude "Rename the 'User' type to 'UserProfile' across
the entire monorepo. Update:
1. packages/types/models.ts (definition)
2. All imports in apps/web
3. All imports in apps/api
4. All imports in packages/ui
Ensure no breaking changes."

Claude Code performs atomic refactoring:

## Refactoring Summary

Files modified: 24
- packages/types/src/models.ts (definition renamed)
- apps/web/src/components/UserCard.tsx
- apps/web/src/hooks/useUser.ts
- apps/api/src/routes/users.ts
- apps/api/src/services/auth.ts
- packages/ui/src/components/Avatar.tsx
... (18 more files)

All TypeScript compilation checks pass.
All tests pass.

Turborepo-Specific Patterns

Configuring Pipeline for AI

// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": []
    },
    "lint": {
      "outputs": []
    },
    "typecheck": {
      "dependsOn": ["^build"],
      "outputs": []
    }
  }
}

AI-Assisted Build Debugging

claude "Our Turbo build is failing with circular dependency
errors. Analyze the dependency graph and fix the issue."

Claude Code investigates:

## Build Analysis

Found circular dependency:
packages/utils → packages/types → packages/utils

Chain:
1. packages/utils imports formatDate from packages/types
2. packages/types imports ValidationError from packages/utils

Solution:
Move ValidationError to packages/types/errors.ts
Update imports in packages/utils to use packages/types

Executing fix...

Nx-Specific Patterns

Using Nx Generators with AI

claude "Use Nx to generate a new React library for charts.
Configure it with our existing Tailwind and testing setup."
# AI executes
npx nx generate @nx/react:library charts \
  --directory=packages/charts \
  --style=tailwind \
  --unitTestRunner=vitest \
  --bundler=vite

Affected Analysis

claude "What packages will be affected if I modify
packages/database/schema.prisma?"
# AI runs
npx nx affected:graph --base=main

# Returns
Affected projects:
- packages/database (modified)
- packages/types (depends on database)
- apps/api (depends on database)
- apps/web (depends on types)
- apps/admin (depends on types, database)

Workspace-Wide Operations

Bulk Updates

claude "Update all packages to use the new logger from
packages/utils/logger instead of console.log. Apply to:
- All apps
- All packages except utils itself
Follow existing import patterns."

Dependency Synchronization

claude "Ensure all packages use the same version of React.
Check for version mismatches and update package.json files."

Best Practices for Monorepo AI Development

  1. Keep Context Files Updated: Maintain .claude/context.md
  2. Use Workspace Protocols: "workspace:*" for internal deps
  3. Consistent Tooling: Same testing, linting across packages
  4. Explicit Boundaries: Clear package responsibilities
  5. Automated Checks: CI validates cross-package changes

Module Summary

You've learned how to:

  • Make AI-driven architectural decisions
  • Build full-stack features with coordinated AI
  • Manage monorepo complexity with AI assistance

Next, we'll tackle large codebase management—working with AI on codebases with hundreds of thousands of lines. :::

Quiz

Module 2: Complex Project Architecture with AI

Take Quiz