Project Structure Optimized for AI
You ask the AI to add a new API endpoint. It finds your route handler, but then spends 8,000 tokens reading through a 2,000-line “utils.ts” file looking for your validation helpers. They are in there — along with 40 other unrelated functions. The AI gets confused, picks the wrong helper, and generates code that breaks existing functionality.
The same task in a well-organized project takes a fraction of the context. The AI finds src/validators/user.ts immediately, reads 80 lines, and generates correct code on the first attempt.
File organization is not just about human readability. It is about AI navigability. The easier your codebase is to traverse, the less context the AI wastes on exploration and the better its output quality.
What You’ll Walk Away With
Section titled “What You’ll Walk Away With”- A project structure pattern optimized for AI-assisted development
- Guidelines for file size, naming, and module boundaries that help AI tools
- Strategies for organizing monorepos and large codebases for AI consumption
- Prompts for having the AI analyze and improve your existing structure
Why File Organization Matters for AI
Section titled “Why File Organization Matters for AI”AI coding assistants navigate your codebase in two ways:
- File reading. The AI reads files to understand context. Every line it reads consumes tokens.
- Search. The AI searches by filename, content, or semantic meaning. Clear naming makes search results more relevant.
Poor organization hurts both pathways:
- Giant files force the AI to read thousands of irrelevant lines to find the one function it needs.
- Vague names (utils.ts, helpers.ts, misc.ts) make search results ambiguous and force the AI to read files speculatively.
- Deep nesting increases the number of directory traversals the AI must perform.
- Circular dependencies confuse the AI about module boundaries and lead to incorrect import suggestions.
Principles for AI-Friendly Structure
Section titled “Principles for AI-Friendly Structure”Small, Focused Files
Section titled “Small, Focused Files”Keep files under 300 lines. When a file grows beyond this, the AI must read content it does not need, wasting context. Split by responsibility.
| Instead of | Use |
|---|---|
utils.ts (800 lines, 30 functions) | validators/email.ts, formatters/date.ts, parsers/csv.ts |
api.ts (1,200 lines, all endpoints) | routes/users.ts, routes/billing.ts, routes/notifications.ts |
types.ts (500 lines, all types) | types/user.ts, types/billing.ts, types/notification.ts |
Descriptive Naming
Section titled “Descriptive Naming”The filename should tell the AI what is inside without reading it. Semantic search works better when filenames match the concepts they contain.
| Vague | Descriptive |
|---|---|
helpers.ts | password-hashing.ts |
index.ts (re-exports) | Keep index files thin, under 20 lines |
service.ts | notification-service.ts |
Component.tsx | UserProfileCard.tsx |
Co-locate Related Files
Section titled “Co-locate Related Files”Put implementation, tests, and types together. When the AI reads your implementation, it can find the related test file immediately without searching.
src/services/ notification/ notification-service.ts notification-service.test.ts notification-types.ts README.md # Brief module descriptionCursor’s semantic search indexes your entire workspace. It benefits enormously from descriptive filenames and co-located files because the search can find related code without reading irrelevant files.
Add a .cursor/rules/structure.md to tell Cursor about your conventions:
---description: "Project structure conventions"alwaysApply: true---
## File Organization- Keep files under 300 lines- Co-locate tests with implementations- Use descriptive filenames (notification-service.ts not service.ts)- Split utils by domain (validators/email.ts not utils.ts)Claude Code navigates using file tools (Read, Glob, Grep). Descriptive names make Glob patterns more precise and Grep searches more targeted.
Add conventions to your CLAUDE.md:
## File Organization- Files should be under 300 lines- Tests are co-located: src/services/foo.ts -> src/services/foo.test.ts- Types are co-located: src/services/foo-types.ts- When creating new files, follow existing naming patternsClaude’s auto memory will learn your structure as it works. You can also tell it directly: “remember that we co-locate tests with implementations.”
Codex reads AGENTS.md for project conventions. Document your structure:
## File Organization- Keep files under 300 lines. Split large files by responsibility.- Tests are co-located with implementations.- Use descriptive filenames: notification-service.ts, not service.ts.- Group by feature/domain, not by type (routes, controllers, models).Codex’s file reading is efficient, but clear organization reduces the number of files it needs to inspect.
Organizing for Monorepos
Section titled “Organizing for Monorepos”Monorepos present unique challenges for AI tools because the sheer number of files can overwhelm search and indexing.
Use .cursorignore to exclude irrelevant packages from indexing:
packages/legacy-app/packages/internal-tools/node_modules/dist/When working in a specific package, open only that package as your workspace rather than the monorepo root. This focuses Cursor’s semantic search on the relevant code.
Claude Code reads CLAUDE.md files hierarchically. Place a root CLAUDE.md with shared conventions and package-level CLAUDE.md files with package-specific guidance:
monorepo/ CLAUDE.md # Shared conventions packages/ api/ CLAUDE.md # API-specific commands and patterns web/ CLAUDE.md # Frontend-specific patternsUse --add-dir to give Claude access to shared packages when working in a specific one. Claude automatically loads CLAUDE.md from parent directories.
Codex uses AGENTS.md with nested overrides. Place global instructions at the root and package-specific overrides in subdirectories:
monorepo/ AGENTS.md # Shared conventions packages/ api/ AGENTS.md # API-specific overrides web/ AGENTS.override.md # Frontend overrides (takes priority)Codex concatenates files from root to current directory, with closer files overriding broader guidance.
The .gitignore Effect
Section titled “The .gitignore Effect”Every tool uses .gitignore (and tool-specific ignore files) to skip irrelevant content. Make sure your ignore files exclude everything the AI should not read:
# .gitignore (also respected by AI tools)node_modules/dist/build/.next/coverage/*.min.js*.bundle.jsFailing to ignore build artifacts means the AI might read minified JavaScript or compiled output, wasting massive amounts of context on unreadable content.
When This Breaks
Section titled “When This Breaks”The team resists restructuring. You do not need to reorganize your entire codebase at once. Start by splitting the worst offenders — the 1,000-line files and the catch-all utils. Use the AI to help with the restructuring: it is excellent at extracting functions into separate modules.
Index files become bloated. Index files that re-export everything from a package consume context when the AI reads them. Keep barrel files thin (under 20 lines) or eliminate them in favor of direct imports.
Different tools index differently. Cursor uses semantic embeddings, Claude Code uses file tools (Read, Grep, Glob), and Codex uses its own indexing. A structure that works well for one tool generally works well for all, but pay attention to tool-specific ignore files.
Co-location does not work for shared utilities. Some code genuinely is shared across many features (database connection, logging, error handling). Keep these in a clearly named shared/ or lib/ directory with small, focused files.