Domain Services and Application Services

Created on: 9/19/2025

Updated on: 9/5/2026

5 mins

Domain Services and Application Services

In Domain-Driven Design, our primary goal is to place business logic close to where data lives — inside entities and .
When an entity enforces its own rules, software becomes expressive, cohesive, and easy to maintain.

However, real-world systems often present problems that do not fit naturally inside a single entity.
Actions often require calculations across multiple aggregates or involve coordinating workflows across external systems.

This is where Services come in.
DDD defines two distinct kinds of services: Domain Services and Application Services.
Understanding the boundary between them is essential for keeping models clean and architectures modular.

The Role of Services

A common anti-pattern in object-oriented systems is the anemic domain model: code where entities are empty data bags, and all rules live in massive, unstructured service classes.

DDD prevents this by setting a clear rule:
Always model logic inside the aggregate first. Only reach for a service when the behavior inherently belongs outside an individual entity.

To keep responsibilities sharp, we separate services into two layers:

  • Domain Services: Pure business logic that belongs to the problem domain.
  • Application Services: Workflow orchestration that coordinates use cases for the outside world.

What Is a Domain Service?

A Domain Service represents business logic that cannot be naturally placed inside a single entity or value object.

Characteristics of a domain service:

  • Stateless: It does not hold its own state. It receives domain objects, operates on them, and returns a result.
  • Pure Domain Rules: It contains business calculations, validation across multiple aggregates, or domain policies.
  • No Infrastructure Dependencies: It never talks to databases, message brokers, or external network APIs.

Examples of domain services:

  • A CurrencyConverter that calculates exchange rates between monetary value objects.
  • A TransferPolicy that determines whether funds can be transferred between two independent bank accounts.
  • A PricingCalculator that computes volume discounts across orders and customer loyalty tiers.

Domain services live strictly inside the domain model. They speak the ubiquitous language of the business.

What Is an Application Service?

An Application Service sits one layer above the domain. It is the conductor that orchestrates a specific business use case.

It does not contain domain rules. Instead, it coordinates the steps required to satisfy a user request:

  • It uses a repository port to load aggregates from storage.
  • It invokes methods on the aggregates or domain services to execute the business rules.
  • It persists the updated aggregates back to storage.
  • It dispatches notifications or domain events to external systems.

Think of the application service as a waiter in a restaurant: the waiter does not cook the food (the domain logic), but ensures the order is taken, delivered to the kitchen, and served to the guest.

Example: Placing an Order

Consider what happens when a customer completes a checkout:

  1. The Application Service receives the checkout request.
  2. It fetches the Customer and Order aggregates using their respective repositories.
  3. It calls a PricingService (a Domain Service) to calculate promotional discounts across both aggregates.
  4. It calls order.applyDiscount() (the Aggregate) to enforce state transitions and protect invariants.
  5. It uses the repository to save the updated Order.
  6. It triggers an external payment adapter and publishes an OrderPlaced event.

Notice the separation:

  • The Aggregate protects its own state invariants.
  • The Domain Service calculates business rules spanning multiple concepts.
  • The Application Service orchestrates the sequence of events.

Rules of Thumb for Services

When designing services in your system:

Entities First

Never create a service as a reflex. If a rule can be placed inside an existing aggregate, it belongs in the aggregate.

Keep Domain Services Free of Side Effects

A domain service should perform pure calculations or evaluations. It should not perform database transactions or network calls.

Keep Application Services Thin

An application service should be a thin orchestration layer. If you see complex business rules creeping into an application service, push them down into an aggregate or domain service.

Closing Thoughts

Services bring balance to the tactical toolbox of Domain-Driven Design.
They give us a home for logic that spans multiple boundaries, without forcing concepts into awkward entity shapes or stripping models of their behavior.

By distinguishing between pure Domain Services and orchestrating Application Services, we establish clean architectural seams that make systems easier to test, simpler to evolve, and aligned with business reality.

Together with ubiquitous language, bounded contexts, context maps, aggregates, domain events, and repositories, services complete the essential journey of Domain-Driven Design.

Local Graph