Entity Service
The Entity Service anti-pattern builds one CRUD service per data entity, leaving services anemic and forcing chatty orchestration and distributed transactions. Design capability-based services around business operations using DDD aggregates and event-driven integration.
The Entity Service anti-pattern designs microservices around individual data entities — a Customer service, an Order service, a Product service — where each is essentially a CRUD wrapper over one table. It feels like a natural decomposition because entities are easy to identify, but it splits services along data boundaries rather than business capabilities, leaving the services anemic and forcing real behavior into orchestrators that stitch them together.
Why It Happens
Entities are the most obvious nouns in a domain, so carving a service per entity is an intuitive first move, especially for teams coming from database-centric design. It mirrors normalized table structure, which makes it feel principled. Tutorials and quick demos often present microservices this way. The deeper cause is decomposing by data structure instead of by what the business actually does. Without domain-driven analysis of capabilities and use cases, the data model becomes the default service map, producing one thin service per table.
Why It Hurts
Because each entity service only does CRUD, no single service can fulfill a real business operation. Workflows must orchestrate many entity services, generating chatty cross-network communication where in-process calls would have sufficed. Business logic has no natural home, so it pools in orchestration layers or leaks across services inconsistently — an anemic, distributed version of the anemic domain model. Operations that should be a single transaction now span services, forcing distributed-transaction or saga complexity with all its failure handling. Services are tightly coupled through shared data semantics, so changing one entity's model ripples across the workflows that depend on it. The system gets the operational cost of microservices with little of the autonomy benefit.
Warning Signs
- Services map one-to-one to database tables and offer only create/read/update/delete.
- Real business logic lives in orchestrators, not in the services.
- Common operations require chained calls across many entity services.
- Updates that should be atomic now span multiple services.
- Changing one entity forces changes in many dependent workflows.
Better Alternatives
Design capability-based services organized around what the business does (place an order, process a payment) rather than around data nouns, so a service can complete a meaningful operation on its own. Use Domain-Driven Design to find bounded contexts and aggregates that group entities by behavior and consistency needs, not by table. Where services must collaborate, prefer event-driven integration over chatty synchronous orchestration, reducing coupling and avoiding distributed transactions.
How to Refactor Out of It
Map the real business operations the system performs and see which span multiple entity services — those crossings reveal misplaced boundaries. Regroup entities by the aggregates and bounded contexts that change together, merging entity services into capability services that own the data and logic for a cohesive slice of the domain. Move logic out of orchestrators into the services that now own the relevant behavior. Replace synchronous fan-out with events where eventual consistency is acceptable, eliminating distributed transactions. The goal is services that each complete meaningful work autonomously, communicating sparingly, instead of CRUD shells coordinated from outside.