Skip to main content
RapidDev - Software Development Agency
cursor-tutorial

How to Make Cursor Respect Domain Boundaries

Make Cursor respect domain-driven design boundaries by mapping your bounded contexts in .cursorrules, creating per-domain rules in nested .cursor/rules/ directories, and using @folder context to scope AI suggestions to specific domains. Without boundary awareness, Cursor freely imports across domains and breaks DDD encapsulation.

What you'll learn

  • How to map bounded contexts in .cursorrules for Cursor awareness
  • How to use nested .cursor/rules/ directories for per-domain rules
  • How to prevent cross-domain imports with explicit boundary rules
  • How to scope Composer sessions to specific domains using @folder
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner7 min read10-15 minCursor Pro+, any languageMarch 2026RapidDev Engineering Team
TL;DR

Make Cursor respect domain-driven design boundaries by mapping your bounded contexts in .cursorrules, creating per-domain rules in nested .cursor/rules/ directories, and using @folder context to scope AI suggestions to specific domains. Without boundary awareness, Cursor freely imports across domains and breaks DDD encapsulation.

Teaching Cursor About Domain Boundaries

Cursor treats your entire codebase as one flat context by default. It will import a payment utility into an authentication module or reference user types from an order service without hesitation. Domain-driven design requires strict boundaries between bounded contexts, and this tutorial shows you how to encode those boundaries into rules that Cursor respects. You will create domain maps, set up per-domain rules, and learn prompt patterns that keep AI suggestions within the correct domain.

Prerequisites

  • Cursor installed (Pro recommended for larger projects)
  • A project organized by domain or bounded context
  • Basic understanding of DDD concepts (bounded contexts, aggregates)

Step-by-step guide

1

Map your bounded contexts in .cursorrules

Document your domain boundaries in .cursorrules so Cursor understands which modules belong to which domain and what cross-domain communication is allowed. List each domain, its directory, and its public API surface.

.cursorrules
1# .cursorrules
2
3## Domain Boundaries (DDD)
4### Bounded Contexts
5- Auth domain: src/domains/auth/ handles authentication, sessions, tokens
6- Orders domain: src/domains/orders/ handles order lifecycle, cart, checkout
7- Payments domain: src/domains/payments/ handles payment processing, refunds
8- Users domain: src/domains/users/ handles user profiles, preferences
9
10### Cross-Domain Rules
11- Domains communicate ONLY through their public API (index.ts exports)
12- NEVER import internal files across domains (no deep imports)
13- Shared types go in src/shared/types/ not duplicated per domain
14- Events between domains use src/shared/events/ event bus
15- Each domain has its own repository never query another domain's tables directly

Pro tip: Add a visual directory map to .cursorrules. Cursor reads it and understands the hierarchy better than prose descriptions.

Expected result: Cursor understands your domain boundaries and avoids cross-domain imports in generated code.

2

Create nested per-domain rules

Place .cursor/rules/ directories inside each domain folder. These rules auto-attach when Cursor is editing files within that domain, reinforcing the boundary without you needing to mention it in every prompt.

src/domains/orders/.cursor/rules/boundary.mdc
1---
2description: Orders domain boundary rules
3globs: "src/domains/orders/**"
4alwaysApply: false
5---
6
7- This is the Orders bounded context
8- Only import from: src/domains/orders/**, src/shared/**
9- NEVER import from: src/domains/auth/**, src/domains/payments/**, src/domains/users/**
10- Communicate with other domains through the event bus: src/shared/events/
11- Repository: src/domains/orders/repositories/ only access orders tables
12- Public API: src/domains/orders/index.ts only these exports are visible to other domains
13- Types: use OrderAggregate, OrderItem, OrderStatus from this domain's types/

Pro tip: Nested rules directories auto-attach for files in their parent directory. You do not need glob patterns when using this approach.

Expected result: When editing any file in the orders domain, Cursor automatically enforces boundary rules.

3

Scope Composer sessions to a single domain

When working within one domain, use @folder to scope Cursor's context. This prevents it from pulling in code from other domains as context. Open Composer with Cmd+I and reference only the relevant domain folder.

Cursor Composer prompt
1// Prompt to type in Cursor Composer (Cmd+I):
2// @src/domains/orders/ @src/shared/types/
3// Add a cancelOrder function to the OrderService.
4// Requirements:
5// - Only use types and repositories from the orders domain
6// - Emit an OrderCancelled event through the shared event bus
7// - Do NOT import anything from payments or users domains
8// - Update order status to 'cancelled' and record cancellation reason

Pro tip: Start each Composer session by referencing the domain folder and shared types. This sets the context boundary for the entire session.

Expected result: Cursor generates code within the orders domain boundary, using only allowed imports.

4

Generate domain events for cross-domain communication

When domains need to communicate, use Cursor to generate event-based integration rather than direct imports. Reference both domains' public APIs and the shared event bus to generate proper event publishing and subscription code.

Cursor Chat prompt
1// Prompt to type in Cursor Chat (Cmd+L):
2// @src/shared/events/eventBus.ts
3// @src/domains/orders/index.ts @src/domains/payments/index.ts
4// Generate an event flow for order payment:
5// 1. Orders domain publishes OrderCreated event with orderId and totalCents
6// 2. Payments domain subscribes and initiates payment processing
7// 3. Payments domain publishes PaymentCompleted or PaymentFailed event
8// 4. Orders domain subscribes and updates order status
9// Keep all domain internals encapsulated — only use public API exports.

Expected result: Cursor generates event definitions, publishers, and subscribers that respect domain boundaries.

Complete working example

src/domains/orders/.cursor/rules/boundary.mdc
1---
2description: Orders bounded context rules
3globs: "src/domains/orders/**"
4alwaysApply: false
5---
6
7# Orders Domain Boundary
8
9## Allowed Imports
10- `src/domains/orders/**` all internal modules
11- `src/shared/types/**` shared type definitions
12- `src/shared/events/**` event bus for cross-domain communication
13- `src/shared/utils/**` shared utilities (logging, validation)
14
15## Forbidden Imports
16- `src/domains/auth/**` use events for auth-related flows
17- `src/domains/payments/**` use events for payment flows
18- `src/domains/users/**` use events or shared types for user data
19
20## Public API
21Only these exports are visible to other domains:
22- `OrderService` the main service class
23- `OrderAggregate` the order entity type
24- `OrderStatus` the status enum
25- `OrderCreated`, `OrderCancelled` domain events
26
27## Repository Rules
28- Only access: orders, order_items, order_history tables
29- Never JOIN with tables from other domains
30- Use the shared event bus for data from other domains
31
32## Domain Event Patterns
33- Publish events for state changes: OrderCreated, OrderUpdated, OrderCancelled
34- Subscribe to external events: PaymentCompleted, PaymentFailed
35- Events are defined in src/shared/events/orderEvents.ts

Common mistakes when making Cursor Respect Domain Boundaries

Why it's a problem: Not listing forbidden imports explicitly per domain

How to avoid: Create per-domain .mdc files with explicit Allowed Imports and Forbidden Imports sections.

Why it's a problem: Using @codebase instead of @folder for domain-scoped work

How to avoid: Use @folder references scoped to the specific domain directory and shared types only.

Why it's a problem: Sharing database repositories across domains

How to avoid: Add a rule requiring each domain to own its own tables. Cross-domain data flows through events or API calls, never shared database queries.

Best practices

  • Map all bounded contexts in .cursorrules with directories, allowed imports, and public APIs
  • Use nested .cursor/rules/ in each domain directory for auto-attaching boundary enforcement
  • Scope Composer sessions with @folder to prevent cross-domain context pollution
  • Generate domain events for cross-domain communication instead of direct imports
  • Define public API surfaces (index.ts exports) per domain and reference them in rules
  • Keep shared types in src/shared/types/ rather than duplicating across domains
  • Start new Composer sessions when switching between domains to reset context

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I have a DDD project with these bounded contexts: Auth, Orders, Payments, Users. Each is in src/domains/{name}/. Generate a cross-domain event system where orders publishes OrderCreated, payments subscribes and processes payment, then publishes PaymentCompleted. No direct imports between domains.

Cursor Prompt

@src/domains/orders/ @src/shared/types/ Add a cancelOrder function to OrderService. Only use imports from the orders domain and shared types. Emit an OrderCancelled event through the shared event bus. Do NOT import from auth, payments, or users domains. Update order status and record cancellation reason.

Frequently asked questions

How does Cursor handle domain boundaries by default?

It does not. Cursor treats your entire codebase as flat context and will freely import across any directory. You must explicitly define boundaries in .cursorrules and per-domain rule files.

Can Cursor enforce DDD aggregate rules?

Yes, with explicit rules. Define your aggregates, their boundaries, and what can reference them in .cursor/rules/ files. Cursor will follow these constraints when generating code within the domain.

Should I use one .cursorrules file or per-domain rules?

Both. Use .cursorrules for the global domain map and cross-cutting rules. Use nested .cursor/rules/ directories in each domain for domain-specific constraints. The nested rules auto-attach when editing files in that domain.

How do I handle shared code between domains?

Create a src/shared/ directory for types, utilities, and the event bus. List it as an allowed import in every domain's rules. Never put domain-specific logic in shared — only truly cross-cutting concerns.

What if Cursor still imports across domain boundaries?

Rules can drift in long sessions. Start a new chat with Cmd+N and explicitly reference the domain folder with @folder. If the problem persists, copy the boundary rules directly into your prompt.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.