If you build .NET services that need to talk to each other without locking up the calling thread, NServiceBus on Amazon SQS is a sensible default. It handles low-level serialization, threading, and transaction management out of the box. You add the NuGet package, configure an endpoint, and start treating messages as commands and events instead of raw payloads.
This guide covers core concepts, a practical setup walkthrough, and the trade-offs you need to understand before committing.
The moving parts you actually need to know
Five terms show up everywhere in NServiceBus docs. Learn these and the rest of the system makes sense.
- Message.** A class that implements ICommand or IEvent. Commands ask for something to happen. Events announce that something has happened.
- Endpoint.** A logical address that sends and receives messages. A deployed copy of that endpoint is an instance.
- Hosting.** The runtime that runs an endpoint instance. Multiple instances can share a process, though for serious workloads you usually do not want them to.
- Transport.** The plumbing that moves messages between endpoints. SQS is one option; Azure Service Bus, RabbitMQ, and SQL Server are others.
- Publish and subscribe.** The pattern that lets one publisher notify many subscribers without knowing who they are.
The reference walkthrough, in our own words
The original setup uses a user-messages class library with two types. CreateUserCommand is a request to make a new user. UserCreatedEvent is the broadcast that a user has been made. The receiver is a console app named "user-service". In Program.cs the developer configures an endpoint, plugs in the SQS transport, and calls EnableInstallers so the required queues and permissions are created the first time the app runs.
On the sender side, the configuration is similar. You build an endpoint, point it at SQS, and call Send on a configured IMessageSession. The bus handles serialization and threading for you.
A few things the original mentions only in passing and that teams should flag:
- EnableInstallers** is convenient in dev. In production, treat the queue and policy setup as infrastructure-as-code, not something the app quietly creates.
- Put message types in their own assembly.** Sharing a contract library is what keeps publisher and subscriber in sync.
- Use structured logging around the handler.** NServiceBus surfaces retries and timeouts as regular messages.
Worked example: a small but realistic pipeline
Say you run a .NET API on AWS and want a background worker to handle user creation.
- Define CreateUserCommand and UserCreatedEvent in a shared class library referenced by both the API and the worker.
- In the API project, configure an endpoint, then call session.Send(new CreateUserCommand(…)) instead of doing the work inline.
- In the worker project, implement IHandleMessages<CreateUserCommand>. Inside, do the database work and call session.Publish(new UserCreatedEvent(…)) when done.
- A separate email service subscribes to UserCreatedEvent. It does not know about the API.
When to use NServiceBus vs. Raw SQS
| Scenario | NServiceBus | Raw SQS Client |
|---|---|---|
| Multiple services, complex routing | Strong | Manual correlation |
| Retries and dead-letter handling | Built-in | DIY |
| Team size | Small to medium | Very small |
| Learning curve | Steeper upfront | Lower barrier |
| Cost | Framework overhead | Direct pricing |
Our analysis
NServiceBus is not the cheapest or simplest option. AWS offers the SQS .NET client directly, and for a single queue with a few workers that may be enough. The case for NServiceBus is when your team is tired of writing the same boilerplate for retries, dead-lettering, and message correlation. The framework is opinionated, and that is a feature if you want consistency across services.
The trade-off is coupling to Particular Software's roadmap, and a learning curve for developers who have only ever done request-response. The productivity gain is real once the team gets over the hump.
What to watch:** how SQS message size limits affect your payloads (the reference flags this as a separate concern), and the cost of SQS requests at high throughput. Both bite quietly.
Who should care
- Backend .NET developers** building microservices on AWS—NServiceBus on SQS is a solid default.
- Platform engineers**—consider the infrastructure-as-code angle for queue setup.
- Small teams with simple workflows**—the raw SQS client may be all you need.
Bottom line
Use NServiceBus if you are building message-driven services in .NET and you want the framework to handle the boring parts. Stick with the raw SQS client if your workflow is simple and your team is small. Productionize the infrastructure setup before you trust it.
Key takeaways
- NServiceBus on SQS is a solid default for .NET teams building event-driven services.
- EnableInstallers is a development convenience, not a production pattern.
- Share message contracts in a separate class library so publishers and subscribers stay aligned.
- Watch SQS message size limits and request costs; both become problems at scale.
Frequently asked questions
Do I need EnableInstallers in production?
Not really. It is convenient for local dev because it creates the SQS queues for you. In production, define the queues and IAM policies in your infrastructure code.
How do SQS message size limits affect NServiceBus?
SQS has a hard cap on individual message size. Large payloads should use the S3 large message store pattern, which NServiceBus supports out of the box.
Can I mix NServiceBus endpoints with raw SQS consumers?
Yes, but you lose NServiceBus features like retries and correlation tracking. Keep a clean boundary so the raw consumers do not quietly become the weak link.
Does this work with AWS Lambda?
NServiceBus supports Lambda hosting through a dedicated package. The trade-off is cold starts and execution time limits, so design handlers to be quick.
How is this different from Azure Service Bus?
Functionally similar idea, different transport. SQS is cheaper at low volume and integrates well with the rest of AWS. Azure Service Bus has features like sessions and topics that SQS lacks. Pick based on your cloud and your team.