Keep Cursor aligned with microservices architecture by defining service boundaries in .cursorrules, creating per-service .cursor/rules/ directories that enforce API contracts and isolation, and using @folder context to scope prompts to individual services. Without explicit boundaries, Cursor generates monolithic code that violates service isolation.
Teaching Cursor About Service Boundaries
Cursor defaults to monolithic patterns: shared databases, direct function calls, and tightly coupled modules. In a microservices architecture, each service must own its data, communicate through APIs or events, and maintain independent deployment. This tutorial shows you how to encode these constraints so Cursor generates code that respects service boundaries, uses proper inter-service communication, and follows your API contract conventions.
Prerequisites
- Cursor installed (Pro+ recommended)
- A microservices project with defined service boundaries
- API contract definitions (OpenAPI, protobuf, or similar)
- Understanding of microservices communication patterns
Step-by-step guide
Map your service architecture in .cursorrules
Map your service architecture in .cursorrules
Document all services, their responsibilities, and allowed communication paths. This gives Cursor a high-level understanding of your architecture that applies across all prompts.
1# .cursorrules23## Microservices Architecture4### Services5- user-service (port 3001): auth, profiles, preferences6- order-service (port 3002): orders, cart, checkout7- payment-service (port 3003): payment processing, refunds8- notification-service (port 3004): email, push, SMS910### Rules11- Each service has its OWN database — never share tables12- Services communicate via REST APIs or event bus (RabbitMQ)13- Never import code directly from another service14- API contracts defined in /contracts/{service}.openapi.yml15- Use service client libraries for inter-service calls16- Each service is independently deployableExpected result: Cursor understands service boundaries and generates code within the correct service context.
Create per-service auto-attaching rules
Create per-service auto-attaching rules
Place .cursor/rules/ in each service directory with service-specific constraints. These rules auto-attach when editing files in that service, ensuring correct database, API, and dependency usage.
1---2description: Order service boundaries3globs: "services/order-service/**"4alwaysApply: false5---67- Database: orders_db (PostgreSQL) — only access orders, order_items, cart tables8- API base: /api/orders9- Dependencies: @company/user-client for user lookups, @company/payment-client for payments10- NEVER import from services/user-service/ or services/payment-service/ directly11- Publish events: OrderCreated, OrderCancelled, OrderCompleted12- Subscribe to: PaymentCompleted, PaymentFailed13- Port: 3002, configured via ORDER_SERVICE_PORT env varPro tip: List the exact database tables each service owns. Cursor will only generate queries for those tables.
Expected result: Service-specific rules auto-attach when editing files in the order service.
Generate inter-service communication code
Generate inter-service communication code
When generating code that involves multiple services, reference the API contracts and service client libraries. Cursor generates proper HTTP client calls or event publishing instead of direct imports.
1// Prompt to type in Cursor Composer (Cmd+I):2// @contracts/user-service.openapi.yml @services/order-service/src/clients/3// Generate a function in the order service that:4// 1. Fetches user details from the user service via REST client5// 2. Creates an order in the local orders_db6// 3. Publishes an OrderCreated event to RabbitMQ7// 4. Returns the created order with user name8// Use the existing service client pattern from the clients/ directory.9// Handle: user not found, service unavailable, timeout scenarios.Pro tip: Always reference the API contract file (@contracts/*.openapi.yml) so Cursor generates correct request/response types.
Expected result: Cursor generates code that uses HTTP clients and events for cross-service communication instead of direct imports.
Generate API contract files with Cursor
Generate API contract files with Cursor
Use Composer to generate OpenAPI specifications from your existing service code, or generate service implementations from existing contracts. This keeps contracts and implementations in sync.
1// Prompt to type in Cursor Composer (Cmd+I):2// @services/order-service/src/routes/3// Generate an OpenAPI 3.1 specification for the order service.4// Include all endpoints from the routes directory.5// For each endpoint: path, method, request body, response schema, error responses.6// Save to contracts/order-service.openapi.ymlExpected result: A complete OpenAPI specification matching your service's actual endpoints.
Complete working example
1---2description: Order service microservice boundaries3globs: "services/order-service/**"4alwaysApply: false5---67# Order Service Boundary Rules89## Owned Resources10- Database: orders_db (PostgreSQL)11- Tables: orders, order_items, cart, cart_items12- API path prefix: /api/orders13- Port: 3002 (ORDER_SERVICE_PORT)1415## Allowed Dependencies16- Direct: express, pg, zod, amqplib17- Service clients: @company/user-client, @company/payment-client18- Shared: @company/shared-types, @company/logger1920## Forbidden21- NEVER import from services/user-service/ or services/payment-service/22- NEVER query tables owned by other services23- NEVER use shared database connections across services2425## Inter-Service Communication26- User lookups: UserClient.getUser(userId) — REST call to user-service27- Payment: PaymentClient.createCharge(orderId, amount) — REST call28- Events published: OrderCreated, OrderUpdated, OrderCancelled29- Events consumed: PaymentCompleted, PaymentFailed, UserDeleted3031## Error Handling32- Wrap all service client calls in try/catch33- Handle: ServiceUnavailable, Timeout, NotFound34- Use circuit breaker pattern for external service calls35- Return appropriate HTTP status codes (502 for upstream failures)Common mistakes when keeping Cursor Aligned with Microservices Architecture
Why it's a problem: Letting Cursor import code directly between services
How to avoid: Add explicit FORBIDDEN import rules per service and require service client libraries for cross-service communication.
Why it's a problem: Not defining database ownership per service
How to avoid: List the exact tables each service owns in its .cursor/rules/ file.
Why it's a problem: Generating synchronous cross-service calls for all communication
How to avoid: Define which operations use REST (queries) vs events (state changes) in your service rules.
Best practices
- Map all services, their databases, and communication paths in .cursorrules
- Create per-service .cursor/rules/ with owned resources and forbidden imports
- Reference API contract files when generating inter-service communication code
- Use @folder scoped to individual services to prevent cross-service context
- Define event-driven vs synchronous communication patterns per operation type
- Generate API contracts from code and code from contracts to keep them in sync
- Handle service unavailability (timeout, circuit breaker) in all cross-service calls
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
Generate a microservice endpoint that creates an order. It must: fetch user details from a separate user service via REST, save the order to a local database, publish an OrderCreated event to RabbitMQ, and handle upstream service failures gracefully.
@services/order-service/src/ @contracts/user-service.openapi.yml Generate a createOrder endpoint that fetches user via UserClient, saves to orders_db, publishes OrderCreated event to RabbitMQ. Handle: user not found, payment service unavailable, timeout. Follow the boundary rules in .cursor/rules/.
Frequently asked questions
How do I prevent Cursor from generating monolithic code?
Define service boundaries explicitly in .cursorrules with owned resources, allowed dependencies, and forbidden imports. Create per-service .cursor/rules/ and always scope prompts with @folder to the specific service.
Can Cursor generate API contracts between services?
Yes. Reference your service routes with @file and ask Cursor to generate an OpenAPI specification. Or provide an existing contract and ask Cursor to generate a service client library from it.
Should I open separate Cursor windows per service?
Yes, for large microservice projects. Each window indexes only that service's code, improving performance and ensuring the AI stays within service boundaries.
How does Cursor handle shared code in microservices?
Create a shared packages directory (e.g., packages/shared-types) and list it as an allowed import in every service's rules. Only put truly cross-cutting types and utilities in shared packages.
Can Cursor generate Docker Compose for microservices?
Yes. Reference all service Dockerfiles and the service architecture from .cursorrules. Prompt Cursor to generate a docker-compose.yml with separate containers, networking, and health checks per service.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation