How to Set Up Cursor Rules Files for Multi-Language Monorepos: Per-Directory AI Behavior & Team Conventions
Setting Up Cursor Rules for Multi-Language Monorepos
Cursor’s .cursor/rules system lets you define AI behavior at the project, directory, and framework level. In a monorepo with multiple languages, this means you can give the AI completely different instructions depending on which file or folder you’re working in — while still sharing team-wide conventions from a single source of truth.
This guide walks you through creating a rules hierarchy for a real-world monorepo with a Python backend, React frontend, and Go microservices.
Step 1: Understand the Rules Hierarchy
Cursor loads rules in a cascading order. More specific rules override general ones:
- Project root rules —
.cursor/rulesat the repo root apply to every file.- Directory-level rules —.cursor/rulesinside any subdirectory override root rules for files in that subtree.- File-pattern rules — Rules files can target specific globs (e.g.,*.test.ts).This cascading model is what makes monorepo setups powerful. You define shared conventions once at the root, then specialize per service or language.
Step 2: Create the Root Rules File (Shared Team Conventions)
At your repository root, create the directory and rules file:
mkdir -p .cursor
touch .cursor/rules
Add shared team conventions that apply everywhere:
# .cursor/rules (project root)
You are working in a monorepo with the following structure:
- /frontend — React 18 + TypeScript app
- /backend — Python 3.12 FastAPI service
- /services/auth — Go 1.22 authentication microservice
- /shared/proto — Protocol Buffer definitions
Team Conventions
- Use conventional commits: feat:, fix:, chore:, docs:
- All public functions must have docstrings or JSDoc comments
- Never commit secrets or API keys — use environment variables
- Prefer composition over inheritance
- Write unit tests for all business logic
- Use ISO 8601 date formats everywhere
- Error messages must be user-friendly and internationalization-ready
Code Review Standards
- Functions should do one thing
- Maximum function length: 40 lines
No magic numbers — use named constants
Step 3: Add Per-Directory Language-Specific Rules
Frontend (React + TypeScript)
# frontend/.cursor/rules
You are working in a React 18 + TypeScript frontend.
## Framework Rules
- Use functional components with hooks exclusively
- State management: Zustand for global state, useState for local
- Styling: Tailwind CSS utility classes — no inline styles or CSS modules
- Use React Query (TanStack Query) for all API calls
- Forms: React Hook Form with Zod validation schemas
## TypeScript Standards
- Strict mode is enabled — never use `any` type
- Prefer `interface` over `type` for object shapes
- Use barrel exports from each feature directory
- Path aliases: @/components, @/hooks, @/lib, @/types
## Autocomplete Behavior
- When suggesting imports, prefer @/ path aliases over relative paths
- When completing component props, always include TypeScript types
- Suggest React.memo() only for components receiving complex objects
- Default to named exports, not default exports
Backend (Python FastAPI)
# backend/.cursor/rules
You are working in a Python 3.12 FastAPI backend.
## Framework Rules
- Use async def for all route handlers
- Pydantic v2 models for all request/response schemas
- SQLAlchemy 2.0 async ORM for database access
- Alembic for migrations — never modify tables manually
- Dependency injection via FastAPI Depends()
## Python Standards
- Type hints on all function signatures
- Use pathlib.Path, never os.path
- Logging via structlog, not print()
- Ruff for linting and formatting (line length: 99)
## Autocomplete Behavior
- When suggesting imports, group as: stdlib, third-party, local
- Suggest Pydantic Field() with description param for API schemas
- Use Annotated types for FastAPI dependencies
- Always suggest async context managers for DB sessions
Go Microservice
# services/auth/.cursor/rules
You are working in a Go 1.22 authentication microservice.
## Framework Rules
- HTTP framework: standard net/http with chi router
- Use context.Context as first parameter in all functions
- Structured logging: slog package
- gRPC for inter-service communication
## Go Standards
- Follow Effective Go and Go Code Review Comments
- Error wrapping: fmt.Errorf("operation: %w", err)
- Table-driven tests with t.Run subtests
- No init() functions — explicit initialization only
## Autocomplete Behavior
- Suggest error checking immediately after any fallible call
- Prefer returning (result, error) over panicking
- Use constructor functions NewXxx() over struct literals for exported types
Step 4: Add File-Pattern Specific Rules
For even more granular control, you can add rules that target specific file patterns. Create a rules file for test files:
# frontend/.cursor/rules-test
globs: [”/*.test.ts”, “/.test.tsx”, ”**/.spec.ts”]
You are writing tests using Vitest and React Testing Library.
- Use describe/it blocks, not test()
- Prefer userEvent over fireEvent
- Use screen.getByRole() as first choice for queries
- Mock API calls with MSW (Mock Service Worker), not manual mocks
- Each test should follow Arrange-Act-Assert pattern
Test behavior, not implementation details# backend/.cursor/rules-test
globs: [“/test_*.py”, ”/*_test.py”]
You are writing tests using pytest with pytest-asyncio.
- Use fixtures for test data setup
- Use httpx.AsyncClient for API endpoint tests
- Factory pattern for creating test objects
Always test both success and error paths
Step 5: Commit and Share with Your Team
Add all rules files to version control so the entire team benefits:
git add .cursor/
git add frontend/.cursor/
git add backend/.cursor/
git add services/auth/.cursor/
git commit -m "chore: add cursor rules for monorepo AI behavior"
git push origin main
Every team member who pulls the repo will automatically get the same AI behavior in Cursor.
Pro Tips
- Rule specificity wins: If a directory-level rule conflicts with the root rule, the directory-level rule takes precedence. Use this intentionally — put strict rules at the root and relaxed exceptions in specific directories.- Keep rules actionable: Instead of writing “use good variable names,” write “use descriptive camelCase variable names with minimum 3 characters — no single-letter variables except in loop iterators.”- Version your rules: Add a comment like
## v2.1 — Updated 2026-03-15at the top of each rules file so your team can track when conventions changed.- Use rules for onboarding: Add a section explaining architectural decisions so new team members get context directly in their AI suggestions.- Combine with .cursoreignore: Create a.cursoreignorefile at the root to prevent the AI from indexing build artifacts,node_modules, or generated files that would pollute suggestions.
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| Rules not applying in subdirectory | File must be at .cursor/rules inside the directory | Verify the path is frontend/.cursor/rules, not frontend/.cursorrules (legacy format) |
| Glob-based rules ignored | Missing or malformed frontmatter | Ensure the YAML frontmatter starts with --- and globs: uses bracket array syntax |
| Conflicting suggestions between services | Root rules too specific for one language | Move language-specific guidance out of root rules into per-directory files |
| AI still suggests old patterns after rule change | Cursor may cache context | Restart Cursor or open the command palette and run **Cursor: Reload Rules** |
| Rules file too long, AI ignores parts | Context window limitations | Keep each rules file under 500 lines. Split into multiple glob-targeted files if needed |
Can I use both the legacy .cursorrules file and the new .cursor/rules directory?
Cursor supports both formats, but the new .cursor/rules system takes precedence when both exist. The legacy single-file .cursorrules at the project root still works for simple projects, but for monorepos you should migrate to .cursor/rules directory format. This gives you per-directory overrides, glob-based targeting, and cleaner organization. Remove the legacy file after migrating to avoid confusion.
How do I handle rules for shared code that’s used by multiple services?
Create a .cursor/rules file in your shared directory (e.g., shared/proto/.cursor/rules) with cross-cutting conventions like protobuf style guides or shared type definitions. Each consuming service’s rules will still apply when editing files in their own directories. For shared libraries consumed by both Python and Go, focus the shared rules on interface contracts and API design rather than language-specific style.
Is there a maximum file size or rule count limit for Cursor rules?
There is no hard-coded limit, but practical limits exist due to the AI’s context window. Rules files exceeding approximately 500 lines may be partially ignored as the AI prioritizes the most relevant sections. Best practice is to keep each rules file focused and under 300 lines. Use multiple glob-targeted rule files to split concerns rather than creating one massive file. This also improves relevance — the AI only loads rules that match the file you’re currently editing.