TurboMediator

Comparison

How TurboMediator compares to MediatR and MassTransit

This page compares TurboMediator against the two most referenced .NET libraries in this space: MediatR (the original mediator library) and MassTransit (the distributed messaging framework).

These libraries solve different problems. MassTransit is a distributed message bus — comparing it here is useful because teams sometimes reach for it when they only need in-process messaging. MediatR is the closest direct competitor.


Feature Matrix

FeatureMediatRMassTransitTurboMediator
Core
Request / Response
Notifications / Events
Streaming
Pipeline behaviors
Performance
Source-generated dispatch (no reflection)
Native AOT supportPartial
Compile-time missing handler detection
Zero-overhead in-process dispatch
Cross-cutting Concerns
Built-in caching
Built-in validation
FluentValidation integrationCommunity
Rate limiting
Distributed locking
Feature flags
Resilience
Retry
Circuit breaker
Timeout
Fallback
Hedging
Observability
OpenTelemetry tracingCommunity
MetricsCommunity
Structured loggingCommunity
Correlation ID propagation
Health checks
Workflows
Sagas
Saga persistence (EF Core)
State machines
Scheduling / Recurring jobs
Persistence
Transactional outbox
Inbox (deduplication)
Audit trail
EF Core integration
Enterprise
Authorization
Multi-tenancy
Message deduplication
Distributed Messaging
RabbitMQ, Azure Service Bus, etc.
Multiple transport adapters
Developer Experience
CLI tooling
Testing utilities
Licensing
Free for all teams❌¹❌²

¹ MediatR's Community license is free only for companies/individuals with less than $5M USD in annual gross revenue that have never received more than $10M in outside capital. Source: mediatr.io.

² MassTransit v9 transitioned to a commercial licensing model. v8 remains open-source but will only receive security patches until end of 2026. Pricing starts at $400/month for small/medium businesses. Source: MassTransit v9 announcement.


When to Choose What

Choose TurboMediator when

  • You need in-process messaging with the fastest possible dispatch (source-generated, no reflection)
  • You want AOT / trimming support
  • You want a complete pipeline ecosystem — resilience, validation, caching, sagas, scheduling, observability — all built to work together
  • You care about compile-time safety (missing handlers are caught at build time)
  • You need enterprise features like authorization, multi-tenancy, or an audit trail without stitching together separate libraries

Choose MediatR when

  • You have a simple project that only needs request/response dispatch and pipeline behaviors
  • Your team is already familiar with it and the use case doesn't justify a migration
  • Budget and licensing are not a concern

Choose MassTransit when

  • You need distributed messaging across services (RabbitMQ, Azure Service Bus, Amazon SQS, etc.)
  • Your architecture is event-driven across process boundaries rather than within a single process
  • You need distributed transaction choreography with Routing Slips

MassTransit and TurboMediator are not mutually exclusive. A common architecture uses MassTransit for cross-service messaging and TurboMediator for in-process command/query dispatch within each service.


Performance Difference

The main performance differentiator is how message dispatch works under the hood.

ApproachDispatch mechanismRuntime cost
MediatRReflection + Dictionary<Type, object> lookupAllocation + reflection per call
MassTransit (in-process)Expression-compiled delegatesOne-time compilation cost
TurboMediatorSource-generated switch expressionZero — resolved at compile time

TurboMediator's source generator emits code like this at build time:

// Generated — no reflection, no dictionary lookup
public ValueTask<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken ct) =>
    request switch
    {
        CreateOrderCommand r => (ValueTask<TResponse>)(object)_createOrderHandler.Handle(r, ct),
        GetOrderQuery r      => (ValueTask<TResponse>)(object)_getOrderHandler.Handle(r, ct),
        // ... all registered handlers
        _ => ThrowUnknownRequest<TResponse>(request)
    };

This means no heap allocations for the dispatch itself and full inlining by the JIT.

On this page