Updated on

Rebus is the strongest MassTransit alternative for most .NET teams: it is MIT-licensed, free at any company size, and small enough to read in an afternoon. NServiceBus is the alternative to reach for when we are buying support and tooling rather than saving money.

The reason people search for an alternative at all is commercial: MassTransit moved to a paid, source-available licence from v9, so the free paths are a 100% discount organisations under $1M revenue may qualify for, staying on v8, or moving off. Which of the three fits depends on transports, saga support, and budget. We compare all three on each below.

To download the source code for this article, you can visit our GitHub repository.

Related Articles: Publish MediatR Notifications in Parallel · How to Use the REPR Pattern in .NET

Introducing the Contenders

For messaging in .NET, Rebus, NServiceBus, and MassTransit are the top choices, so let’s examine what each offers.

First, let’s define a simple message:

public class Message
{
    public string MessageId { get; set; } = string.Empty;
    public string Content { get; set; } = string.Empty;
}

Further in the article, we will be handling messages of this type.

Rebus

Rebus is an open-source, lightweight service bus focused on simplicity and ease of use. It requires minimal setup, allowing developers to implement messaging systems quickly.

Rebus describes itself the same way its users do: “Rebus is a lean service bus implementation for .NET” (rebus-org/Rebus, read 2026-08-09), built with as few dependencies as possible.

Rebus’s biggest advantage is its flexibility and extendability, which allows us to adapt it to our project’s specific requirements.

Now, let’s configure Rebus:

builder.Services.AddRebus(configure => configure
    .Transport(t => t.UseInMemoryTransport(new InMemNetwork(true), "MyQueue"))
    .Routing(r => r.TypeBased().MapAssemblyOf<Message>("MyQueue")));
builder.Services.AutoRegisterHandlersFromAssemblyOf<Program>();

Here, we set up Rebus to use an in-memory transport layer and route all messages of Message type to the designated queue. 

Lastly, the AutoRegisterHandlersFromAssemblyOf<Program>() method registers all handlers from our assembly.

In brief, Rebus is ideal for small to medium applications where simplicity and ease of use are priorities. Our guide on getting started with Rebus in .NET walks through a first project end to end.

NServiceBus

Next is NServiceBus, a feature-rich service bus designed for enterprise-level applications. It offers advanced capabilities that make it suitable for large-scale enterprise systems.

What sets NServiceBus apart is its suite of monitoring and debugging tools, such as ServicePulse and ServiceInsight. These tools provide real-time visibility into our messaging system, making it easier to maintain and troubleshoot.

However, setting up NServiceBus requires more configuration than Rebus, but this comes with greater control and a rich set of features:

builder.Host.UseNServiceBus(context =>
{
    var endpointConfiguration = new EndpointConfiguration("HandlerEndpoint");

    var transport = endpointConfiguration.UseTransport<LearningTransport>();
    var serialization = endpointConfiguration.UseSerialization<SystemJsonSerializer>();

    var routing = transport.Routing();
    routing.RouteToEndpoint(typeof(Message), "HandlerEndpoint");

    return endpointConfiguration;
});

In this example, we configure NServiceBus to use LearningTransport as a transport layer and route instances of ProcessPayment class to the designated endpoint.

Owing to great commercial support from Particular Software, NServiceBus is a great choice for high-scale enterprise applications.

MassTransit

Lastly, MassTransit is another open-source service bus focusing on ease of use and flexibility.

MassTransit strikes a balance between the simplicity of Rebus and the advanced features of NServiceBus, making it a versatile option for a wide range of applications.

One of the strengths of MassTransit is its fluent configuration APIs, which simplify the setup process. It also supports advanced messaging patterns, including sagas and state machines:

builder.Services.AddMassTransit(x =>
{
    x.AddConsumer<MessageHandler>(); 
    x.UsingInMemory((context, cfg) =>
    {
        cfg.ConfigureEndpoints(context);
    });
});

Similarly, we set up MassTransit to use an in-memory transport layer and configure the MessageHandler as a message consumer.

MassTransit balances performance and complexity, making it useful in medium to large applications. To see it wired to a real broker, read our guide on MassTransit with RabbitMQ in ASP.NET Core.

Supported Transports and Protocols

Next, let’s explore their differences in supported transports.

The choice of transport can significantly impact our messaging system, depending on our existing infrastructure and performance requirements.

Let’s have a look at a quick comparison of supported transports:

TransportRebusNServiceBusMassTransit
ActiveMQNoNoYes
Amazon SQSYesYesYes
Azure Service BusYesYesYes
MSMQYesYesNo
RabbitMQYesYesYes
SQL ServerYesYesYes

As we can see, in addition to the common options, NServiceBus and Rebus also support MSMQ, which can benefit legacy systems or environments requiring specific messaging protocols. When RabbitMQ is the target, our guide on RabbitMQ in ASP.NET Core covers configuring the broker itself.

Saga Implementation

Managing complex, long-running processes often requires coordinating multiple messages and maintaining state across different steps.

This is where sagas come into play. Sagas are a pattern that helps manage such workflows, ensuring data consistency and orchestrating the sequence of operations.

Firstly, we have a choreography-based saga, where we have a message bus that transfers messages between producers and consumers:

choreography-based saga with message bus

Alternatively, we can replace the message bus with a specialized service that orchestrates the saga and thus end up with an orchestration-based saga:

choreography-based saga with specialized service instead of message bus

It is worth noting that all three libraries support both saga pattern implementations.

If you want to read more about implementing the saga pattern, read our articles about NServiceBus and Rebus implementations.

Error Handling and Retries

Error handling is critical in any messaging system, ensuring every message is processed even when unexpected issues occur. Each library offers different mechanisms for handling errors and implementing retry policies.

Error Handling and Retries In Rebus

Rebus provides a straightforward approach to error handling and message retries. By default, Rebus will attempt to process a message multiple times before moving it to an error queue. This behavior ensures that transient issues, such as temporary network glitches or resource contention, do not result in lost messages.

Let’s customize the retry behavior in Rebus using the RetryStrategy() method:

configure.Options(o => o.RetryStrategy(
    maxDeliveryAttempts: 5,
    secondLevelRetriesEnabled: true,
    errorQueueName: "ErrorQueue"
));

In this example, the maxDeliveryAttempts option controls how many times Rebus will retry immediately. The secondLevelRetriesEnabled option ensures Rebus will attempt a delayed retry after the first set fails. Finally, the errorQueueAddress defines error queue where the message moves if all attempts fail.

To explain, the first attempts are immediate retries, meaning Rebus will quickly retry processing the message without delay. If all attempts fail, second-level retries introduce a delay before another retry attempt instead of immediately moving the message to the error queue.

These delays allow temporary conditions, like network instability or external service unavailability, to be resolved.

Error Handling and Retries In NServiceBus

NServiceBus also provides built-in retry mechanisms that handle both immediate and delayed retries.

Let’s configure both immediate and delayed retries using the Recoverability settings:

var recoverability = endpointConfiguration.Recoverability();

recoverability.Immediate(immediate => 
    immediate.NumberOfRetries(3)
);

recoverability.Delayed(delayed =>
{
    delayed.NumberOfRetries(2); 
    delayed.TimeIncrease(TimeSpan.FromSeconds(5));
});

endpointConfiguration.SendFailedMessagesTo("ErrorQueue");

In this example, NServiceBus will attempt immediate retries three times and then perform two delayed retries if the message fails to process. If all retry attempts are unsuccessful, NServiceBus will move the message to the error queue.

Is this material useful to you? Consider subscribing and get ASP.NET Core Web API Best Practices eBook for FREE!

Additionally, NServiceBus allows us to implement custom retry policies by providing a custom recoverability policy:

recoverability.CustomPolicy((config, context) =>
{
    if (context.Exception is TimeoutException)
    {
        return RecoverabilityAction.ImmediateRetry();
    }
    
    return RecoverabilityAction.MoveToError("ErrorQueue");
});

As we can see, NServiceBus will attempt an immediate retry only in the case of a TimeoutException exception. Otherwise, it will redirect the message to an error queue.

Error Handling and Retries In MassTransit

Even MassTransit provides flexible error handling and retry capabilities through its built-in middleware. It allows us to configure retries with various strategies, such as immediate retries, intervals, and exponential back-off.

Let’s define the retry policy with MassTransit:

cfg.ReceiveEndpoint("MyQueue", e => e.UseMessageRetry(r => 
    r.Interval(3, TimeSpan.FromSeconds(2))));

In this example, the Interval() specifies that MassTransit should retry the message three times with a 2-second interval between attempts. If all retry attempts fail, MassTransit will move the message to an error queue.

MassTransit automatically creates error queues by adding _error to the end of each endpoint’s name.

Monitoring and Instrumentation

Monitoring the health and performance of our applications is crucial for spotting potential issues early on. Each library offers different tools and integrations to help us monitor our systems.

Rebus and MassTransit integrate with logging frameworks like Serilog, allowing us to capture logs.

Compared to Rebus and MassTransit, NServiceBus takes monitoring further by providing dedicated tools like ServicePulse and ServiceInsight.

ServicePulse offers real-time monitoring of our endpoints, highlighting failed messages and providing insights into system performance.

ServiceInsight allows us to visualize message flows and dive deep into the message processing pipeline, which is invaluable for troubleshooting complex issues.

Additionally, all libraries support OpenTelemetry, which we can use to collect and send metrics to our preferred analytics tools, such as Grafana or Prometheus.

Security Features

Security is the most important concern when transmitting messages between services, especially in distributed systems where data may traverse unsecured networks.

Encryption in Rebus

Rebus provides support for securing messages during transport and at rest. It leverages the security features of the underlying transport mechanisms, such as SSL/TLS encryption for protocols like HTTPS, AMQP, or Azure Service Bus.

Let’s see how we can enable automatic message body encryption in Rebus:

Configure.Options(o => o.EnableEncryption(encryptionKey));

The EnableEncryption() method accepts a Base64-encoded encryption key. By default, Rebus uses this key to encrypt message bodies using the AES algorithm.

If we do not provide a valid key, Rebus will use the built-in .NET functionality to generate the key we can store in the configuration.

We must remember that encryption applies only to the message body, while the data in the message header will still be unencrypted.

Encryption in NServiceBus

Similarly, NServiceBus also offers out-of-the-box support for message encryption.

However, in this case, encryption is property-based to reduce its impact on performance. This means we need to specify which properties in the message body we want to encrypt.

We can enable the encryption of message properties using the EnableMessagePropertyEncryption() method:

var encryptionService = new AesEncryptionService(
    encryptionKeyIdentifier: encryptionKeyId,
    key: Convert.FromBase64String(encryptionKey));

endpointConfiguration.EnableMessagePropertyEncryption(
    encryptionService: encryptionService,
    encryptedPropertyConvention: propertyInfo =>
        propertyInfo.Name.Equals(nameof(Message.Content))
);

In this example, messages are encrypted using the AES algorithm based on the provided encryption key and identifier.

The EnableMessagePropertyEncryption() method instructs NServiceBus to apply encryption to specific message properties.

It accepts the encryptionService instance and function delegate that defines the convention for selecting which properties should be encrypted. The propertyInfo object contains metadata about a message property, such as its name, type, and attributes. In our case, we encrypt the Content property of the Message instance.

Encryption in MassTransit

MassTransit also provides options for securing messages through message serialization.

Let’s set it up:

cfg.UseEncryption(Convert.FromBase64String(encryptionKey));

As easy as that, MassTransit provides a UseEncryption() method that expects a Base64 encoded encryption key.

Community and Support

Community support and available resources are equally important to the provided features, which can greatly influence the long-term success of our project.

On one hand, we have Rebus and MassTransit, which are community-driven projects. In both cases, the maintainers are responsive, and plenty of resources, including tutorials and examples, are available online.

This makes them a great choice for open-source enthusiasts who prefer collaborative support.

On the other hand, NServiceBus offers commercial support through Particular Software, providing professional assistance, training, consultancy, and documentation. This can be a significant advantage for enterprises that require guaranteed support and service-level agreements.

NServiceBus vs MassTransit: Which One Should We Choose?

We choose NServiceBus when the organisation is buying an outcome rather than a library, and MassTransit when the team wants to own the stack itself.

NServiceBus ships the parts that cost the most to build in-house: ServicePulse for live endpoint health, ServiceInsight for message flow forensics, and a vendor with a support contract behind them. That package is priced per endpoint, so the cost grows with the architecture rather than with the team.

MassTransit covers the same messaging ground (sagas, retries, the outbox, request-response) with a larger transport list and no operational UI in the box. Version 8 stays Apache-2.0 and free; version 9 is paid and source-available, with a 100% discount organisations under $1M revenue may qualify for. So it is NServiceBus against a frozen v8, that discount, or a subscription.

For a team of five shipping one service bus, MassTransit v8 or Rebus is enough. For twenty teams that need someone to call at 3am, NServiceBus is what the budget is actually for.

Code Comparison

Now that we know some features, let’s explore how to send and receive messages using each library.

Sending Messages Using Rebus, NServiceBus, and MassTransit

Sending a message typically involves creating a message object and dispatching. Let’s see how we can do this with each library.

But before that, let’s define a common interface:

public interface IMessageSender
{
    Task SendMessageAsync(Message message);
}

The IMessageSender interface defines a SendMessageAsync() method that accepts an instance of the Message class.

Is this material useful to you? Consider subscribing and get ASP.NET Core Web API Best Practices eBook for FREE!

In Rebus, we send messages by injecting the IBus interface into our class and call the Send() method.

Let’s define a RebusMessageSender class:

public class RebusMessageSender(IBus bus) : IMessageSender
{
    public async Task SendMessageAsync(Message message) =>
        await bus.Send(message);
}

Here, we send an instance of a Message class using the IBus instance. Rebus routes the message to the appropriate destination based on the configuration.

With NServiceBus, we use the IMessageSession or IEndpointInstance to send messages.

This time, let’s define a NServiceBusMessageSender class for NServiceBus:

public class NServiceBusMessageSender(IMessageSession messageSession) : IMessageSender
{
    public async Task SendMessageAsync(Message message) =>
        await messageSession.Send(message);
}

In this example, we send a Message instance using the messageSession instance. NServiceBus handles the routing based on the conventions or explicit mappings defined in the endpoint configuration.

MassTransit allows us to send or publish messages using the IBus interface.

Finally, let’s define a MassTransitMessageSender class using MassTransit:

public class MassTransitMessageSender(IBus bus) : IMessageSender
{
    public async Task SendMessageAsync(Message message) =>
        await bus.Publish(message);
}

We use the Publish() method to send the message to any subscribers interested in Message.

If we want to send the message to a specific endpoint, we can use the Send() method instead:

public class MassTransitMessageSender(IBus bus, ISendEndpointProvider sendEndpointProvider)
    : IMessageSender, ICustomMessageSender
{
    public async Task SendMessageAsync(Message message) => 
        await bus.Publish(message);
    
    public async Task SendMessageAsync(Message message, string queueUri)
    {
        var sendEndpoint = await sendEndpointProvider.GetSendEndpoint(new Uri(queueUri));

        await sendEndpoint.Send(message);
    }
}

In this example, we inject ISendEndpointProvider to obtain a reference to a particular endpoint. Then, we use the GetSendEndpoint() method with the URI of the destination queue to get the endpoint. Finally, we use the Send() method to send the message directly to that endpoint.

Receiving Messages Using Rebus, NServiceBus, and MassTransit

Receiving messages involves implementing handlers or consumers that process incoming messages. Each library defines these handlers in its own way.

First, let’s define a common interface:

public interface IMessageHandler
{
    Task Handle(Message message);
}

The IMessageHandler interface defines a Handle() method that accepts an instance of the Message class.

Next, let’s define a shared handler class implementing the IMessageHandler interface that specific message handlers will invoke:

public class MessageHandler : IMessageHandler
{
    public Task Handle(Message message)
    {
        Console.WriteLine($"MessageId: {message.MessageId}, Content: {message.Content}");
        
        return Task.CompletedTask;
    }
}

As we can see, the Handle() method prints to console the details of incoming messages. However, in a real application, this handler would contain business logic.

In Rebus, we implement the IHandleMessages<T> interface for the message type we want to handle. Rebus automatically discovers and registers handlers through dependency injection:

public class RebusMessageHandler(IMessageHandler handler) : IHandleMessages<Message>
{
    public Task Handle(Message message) =>
        handler.Handle(message);
}

In this example, when a Message instance arrives, Rebus invokes the Handle() method.

For NServiceBus, we implement a similar IHandleMessages<T> interface:

public class NServiceBusMessageHandler(IMessageHandler handler) : IHandleMessages<Message>
{
    public Task Handle(Message message, IMessageHandlerContext context) => 
       handler.Handle(message);
}

The Handle() method receives the message and an IMessageHandlerContext, which provides additional capabilities like sending messages, publishing events, or handling retries.

It is worth noting that messages handled by NServiceBus handlers must implement the appropriate interface or follow the convention. 

We define the message convention in the Program.cs file:

var conventions = endpointConfiguration.Conventions();
conventions.DefiningMessagesAs(type => type.Namespace == typeof(Message).Namespace);

This way, we define all types in the same namespace as the Message class as messages.

In MassTransit, we define a consumer by implementing the IConsumer<T> interface:

public class MassTransitMessageHandler(IMessageHandler handler) : IConsumer<Message>
{
    public Task Consume(ConsumeContext<Message> context)
    {
        var message = context.Message;

        return handler.Handle(message);
    }
}

MassTransit uses the Consume() method, which provides a ConsumeContext<T> containing the message and context information. Through this context, we can access headers, publish events, or interact with the message bus.

While the basic concepts are similar across the libraries, each has its own conventions and patterns. Rebus and NServiceBus share a similar interface for handling messages, whereas MassTransit uses the consumer model focusing on the consumption context.

Which of These Libraries Is Free to Use?

Rebus is MIT-licensed and free in commercial products with no revenue threshold and no per-endpoint fee.

MassTransit changed at version 9, announced April 2025 and shipped January 2026. Version 8 stays Apache-2.0 permanently and still ships, but the vendor calls it unsupported with no end date. Version 9 is commercial and source-available, needs a runtime licence key, and organisations under $1M gross annual revenue may qualify for a 100% discount that excludes commercial support.

NServiceBus is commercial, priced per logical endpoint in production, but free for development, and free in production on its Community edition: three endpoints, 10,000 messages a day, forum-only support.

What each cost scales with matters when budgeting. MassTransit’s licence keys off company revenue; NServiceBus keys off the architecture, so splitting a service into two endpoints changes the bill.

So the free answer today is Rebus at any size, MassTransit v8 if we stop upgrading, the v9 discount if we qualify, and NServiceBus inside its Community limits. If cost decides, start with Rebus.

What Are the Best MassTransit Alternatives in .NET?

The three realistic MassTransit alternatives in .NET are Rebus, NServiceBus, and staying on MassTransit v8.

Rebus is the closest like-for-like swap. It is MIT-licensed, handles sagas, retries, and the outbox, and its configuration surface is small enough that a migration is mostly rewriting registration code and handler signatures.

NServiceBus is the move when the driver is operations rather than licence cost. It brings its own monitoring tooling and a support contract, and it is priced accordingly.

Staying on MassTransit v8 is a legitimate third option. It stays Apache-2.0 permanently and the line still ships, but the vendor calls it unsupported and commits to no support window, so it buys time rather than solving the problem.

Wolverine is worth a look for teams that also want the mediator role in the same library, though it is a younger project with a smaller operational track record. Whichever we pick, the transports we already run usually narrow the list faster than any feature comparison does.

CriterionRebusNServiceBusMassTransit
LicenceMIT: free at any revenueCommercial, per logical endpoint in production; free for developmentCommercial and source-available from v9, licence key required at runtime; v8 stays Apache-2.0 permanently
Cost at 20 developersNothingFree on the Community edition (3 endpoints, 10,000 messages/day); quoted per endpoint above itv8 free; on v9, organisations under $1M gross annual revenue may qualify for a 100% discount, otherwise a paid licence
Size of the API to learnSmallLargeMedium
Sagas / process managersYesYesYes
OutboxYesYesYes
Built-in operational UINo (third-party)ServicePulse, ServiceInsightNo (third-party)
Commercial supportCommunityVendor SLA; forum only on the Community editionVendor, but excluded from the 100% discount
Best fitSmall teams, cost-sensitiveEnterprises buying supportTeams already on v8, teams under the discount threshold, or teams paying for v9

Beyond these three, it is worth weighing the Wolverine library, which folds the mediator and service-bus roles into a single package.

Conclusion

We compared the key features, benefits, and use cases of Rebus, NServiceBus, and MassTransit, and the choice comes down to licensing cost, transport support, and how much tooling we want out of the box rather than build ourselves.

Each library has its strengths and is suited for different scenarios. By understanding their capabilities and considering factors like licensing and cost, we can make informed decisions that align with our application’s requirements and our team’s expertise.

Tested with .NET 10.0.10 and MassTransit 8.5.10, the last Apache-2.0 v8 release. The sample stays pinned to the free v8 line rather than the commercial, source-available v9, which also needs a runtime licence key on every machine.