Back to Home

DDD in ASP.NET: scalability issues after 30 aggregates

In ASP.NET projects with more than 30 aggregates, DDD leads to performance degradation due to heavy EF Core queries, explosion of specifications, and transaction complexities. Analysis of problems and recommendations for hybrid approaches: CQRS, Vertical Slices.

Why DDD breaks in large ASP.NET projects with 30+ aggregates
Advertisement 728x90

Scaling DDD in ASP.NET: Challenges Beyond 30 Aggregates

When a project exceeds 30 aggregates in ASP.NET with Entity Framework Core, the principle "one query — one aggregate" leads to critical performance issues. Each aggregate requires full loading with nested objects, generating SQL queries with numerous JOINs. This becomes especially problematic in ERP systems or marketplaces where object graphs reach 5–6 levels of nesting.

A typical Order aggregate query looks like this:

var orders = await context.Orders
    .Include(o => o.Customer)
        .ThenInclude(c => c.Address)
    .Include(o => o.Customer)
        .ThenInclude(c => c.Contacts)
    .Include(o => o.Items)
        .ThenInclude(i => i.Product)
            .ThenInclude(p => p.Category)
    .Include(o => o.Items)
        .ThenInclude(i => i.Discount)
    .ToListAsync();

The resulting SQL contains dozens of LEFT JOINs, significantly slowing execution. Updating a single field in an order header forces loading all OrderItems as part of the aggregate, compounding the performance burden.

Google AdInline article slot

Explosive Growth of Specifications and Their Limits

The Specification pattern encapsulates query logic, but with 30+ aggregates, the collection of Specification classes can grow to hundreds of files. Composition via And/Or results in inefficient SQL due to EF Core’s IQueryable dependency.

Key challenges:

  • ORM-specific: Specifications don’t work with Dapper or gRPC without rewriting.
  • Complex composition: Real-world scenarios involving roles, statuses, and time zones become unwieldy.
  • Abstraction overhead: Time spent on abstractions exceeds actual business logic implementation.

Cross-Aggregate Transactions and Infrastructure Overhead

Scoped DbContext in ASP.NET Core works well for Unit of Work in small projects. In large systems, business workflows often require simultaneous updates across 5+ aggregates: placing an order, processing a payment, reserving inventory, and creating a call center task.

Google AdInline article slot

Available solutions contradict DDD principles:

  • Single database transaction — creates God services and violates aggregate boundaries.
  • Distributed Sagas or Outbox patterns — increase complexity by up to 10x.

As a result, 70% of the codebase becomes infrastructure glue for synchronization, not business logic.

Code Navigation: Thousands of Files and Slowed Iterations

DDD structure (API/Application/Domain/Infrastructure + Features) generates over 1,000 files with 30+ aggregates. Changing a single entity field affects:

Google AdInline article slot
  • Domain entity
  • Fluent API configuration
  • Migration
  • Command
  • Validator (FluentValidation)
  • Handler
  • DTO
  • Mapper (AutoMapper)
  • Specification
  • Tests

This drastically slows development, complicates onboarding, and hinders long-term maintenance.

What Matters Most

  • Performance: Heavy Include/ThenInclude operations produce inefficient SQL, causing API response times to grow exponentially.
  • Specifications: Don’t scale, are tied to EF Core, and composition leads to errors.
  • Transactions: Cross-aggregate operations force trade-offs between DDD ideals and real business needs.
  • Codebase size: Over 1,000 files slow iterations by 50–70%.
  • Hybrid approach: Apply DDD only in the core; use CQRS and Vertical Slices for peripheral concerns.

Recommendations for Migration

For projects with 30+ aggregates, adopt hybrid architectures:

  • CQRS: Separate commands from queries; use read models without Include clauses.
  • Vertical Slices: Group code by feature, minimizing layered complexity.
  • Feature-Sliced Design: Achieve modularity without rigid, onion-like architecture.

These approaches preserve DDD principles in complex domains while simplifying everything else.

— Editorial Team

Advertisement 728x90

Read Next