MediatR: in-process messaging for .NET, and the licence key that now comes with it
Simple, unambitious mediator implementation in .NET
At a glance
- What is it?
- MediatR is a dependency-free in-process mediator for .NET that routes commands, queries and notifications to handlers through Microsoft.Extensions.DependencyInjection. The trade-off is a commercial licence key and a handler layer that not every codebase needs.
- Who is it for?
- Adopt MediatR when you want request and notification dispatch that is decoupled from the code calling it, and when a licence key is acceptable in your build and deployment pipeline. Skip it if a plain interface plus constructor injection already gives you the indirection you need, or if adding a paid dependency to a small service is not worth the paperwork.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 90 days ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What MediatR removes from your call sites
The README describes MediatR as "simple, unambitious mediator implementation in .NET" and "in-process messaging with no dependencies". That framing matters. This is not a broker, a queue or a transport. Everything happens inside one process, and the only external contract MediatR depends on is Microsoft.Extensions.DependencyInjection.Abstractions.
The problem it addresses is the direct call. Without a mediator, a controller or endpoint constructs or injects a service and calls a method on it, so the caller knows the concrete handler type and its method signature. With MediatR the caller sends an IRequest object and receives a response, and the handler that processes it is resolved at runtime from the container. The caller no longer holds a reference to the handler type.
The audience is .NET teams already using the generic host and IServiceCollection, typically ASP.NET Core applications, but the samples directory also includes Autofac, DryIoc, Lamar, LightInject, SimpleInjector, Stashbox and Windsor, so the registration story is not limited to Microsoft's container. The README lists notification and event handling alongside request and response, synchronous and async, which means the same abstraction covers both a single-handler command and a fan-out to many subscribers.
How dispatch actually resolves a handler
MediatR ships four contract types that define the shape of a message: IRequest and its generic variants, INotification, and IStreamRequest. A request maps to exactly one handler; a notification maps to zero or more. The README states that dispatching uses C# generic variance, which is how a single Send call can be typed against the request interface while the container resolves the concrete IRequestHandler<,> implementation underneath.
Registration is where the wiring happens. Calling AddMediatR registers IMediator, ISender and IPublisher as transient, plus concrete implementations of IRequestHandler<,>, IRequestHandler<>, INotificationHandler<>, IStreamRequestHandler<>, IRequestExceptionHandler<,,> and IRequestExceptionAction<,>, all transient. Open generic implementations are registered for INotificationHandler<>, IRequestExceptionHandler<,,> and IRequestExceptionAction<,>.
Transient is worth pausing on. Every resolution produces a new instance, so handlers must not hold state between calls. Behaviors, stream behaviors and pre/post processors are registered explicitly rather than discovered, which means the pipeline order is something you declare. That is a deliberate design choice: it keeps the pipeline readable, but it also means a behavior added to one registration call is invisible to a second AddMediatR call elsewhere in the same container.
Installing MediatR and sending a first request
The README gives two install paths. From the Package Manager Console, Install-Package MediatR. From the .NET Core CLI, the command below. Either one pulls MediatR and its required dependencies from NuGet.
dotnet add package MediatRIf your contracts live in a separate assembly from your handlers, the README points to a second package, MediatR.Contracts, which carries only IRequest (including generic variants), INotification and IStreamRequest. The README names API contracts, GRPC contracts and Blazor as scenarios where that split helps.
Registration goes through IServiceCollection. The README shows both an assembly-containing overload and an explicit assembly overload. The first form scans the assembly that contains the type you name:
services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<Startup>());Behaviors, stream behaviors and pre/post processors are added inside the same configuration callback, and the README includes an AddOpenBehavior overload for open generic behavior types. After this call, resolving IMediator or ISender from the container should return a working instance, and a Send call should reach the handler whose request type it matches. If nothing is resolved, the assembly you named is the first thing to check, because the scan only covers what that assembly contains.
The licence key, and where MediatR looks for it
MediatR is not free to use without a key. The README shows two ways to set one: cfg.LicenseKey inside the AddMediatR callback, or Mediator.LicenseKey when you are not using Microsoft.Extensions.DependencyInjection.
services.AddMediatR(cfg =>
{
cfg.LicenseKey = "<license key here>";
});If no key is set in code, MediatR reads environment variables. MEDIATR_LICENSE_KEY holds a MediatR-specific key. LUCKYPENNY_LICENSE_KEY holds a key shared across Lucky Penny products, and the README notes that AutoMapper reads the same variable, so a shared key must belong to a licence that includes MediatR (a Bundle or MediatR edition). An AutoMapper-only licence will not validate here. Precedence is explicit code first, then MEDIATR_LICENSE_KEY, then LUCKYPENNY_LICENSE_KEY, and the first value found wins.
The README also states that the key does not need to be set on client applications such as Blazor WASM, and that the licence warning can be silenced through logging configuration with builder.Logging.AddFilter("LuckyPennySoftware.MediatR.License", LogLevel.None). Keys are issued at MediatR.io. The repository's LICENSE.md is the file to read for the actual terms; the README does not restate them, and the repository metadata does not carry a standard SPDX identifier, so treat the licence text itself as the source of truth rather than any summary.
Where MediatR is the wrong layer
The most common misreading of MediatR is that it is an architectural requirement. It is a dispatch mechanism. If a class has one caller and one implementation, sending a request object through the container adds a type, a handler class and a registration without removing any coupling that constructor injection had not already removed.
The constraints are concrete. Handlers are registered transient, so any handler that keeps per-request state in a field is a bug waiting for a second resolution. Everything is in-process, so MediatR gives you nothing for cross-service messaging, retries, delivery guarantees or persistence of in-flight work; those are problems for a broker, not a mediator. The pipeline is also explicit: behaviors are added by hand, so a team expecting convention-based discovery will find that the ordering is theirs to maintain.
The licence adds a second kind of constraint. A key has to reach the process, whether through code or one of the two environment variables, and that means secret distribution becomes part of your deployment. The README's note about client applications and the logging filter exists precisely because that distribution is awkward in browser-hosted scenarios. For a small internal service, that overhead may outweigh the benefit of the abstraction entirely.
MediatR alternatives in C# and how they differ
The alternatives people search for split into two groups. The first is another in-process mediator with a different registration model. The second is no mediator at all, which is a legitimate answer.
The real difference between MediatR and a hand-rolled mediator is the registration and pipeline machinery. Writing your own means an interface with a Send method, a dictionary of request type to handler type, and your own resolution logic. That is perhaps a hundred lines, it has no licence key and no environment variable, and it is entirely under your control. What you give up is the parts MediatR already ships: generic variance based dispatch, stream requests, notification fan-out, exception handlers and actions, pre and post processors, and open generic behavior registration. Whether those are worth a dependency and a key depends on how many of them you would otherwise write yourself.
Against a full message broker, the difference is categorical rather than incremental. A broker moves messages between processes and survives restarts. MediatR dispatches inside one process and does not. Choosing MediatR does not preclude a broker later, but the two solve different problems and neither substitutes for the other. The samples directory is the honest signal here: nine sample projects covering different containers and publish strategies, which tells you the project expects you to assemble the surrounding pieces yourself.
Maintenance, upgrades and what a version bump costs
The repository's last push was on 2026-07-02, which is the same date as the v14.2.0 release. The 14.x line moved quickly before that: v14.1.0 on 2026-03-03 and v14.0.0-beta-1 on 2025-11-20. The repository is not archived, and the release cadence is recent enough that a project on 13.x or earlier should expect to do work when it upgrades.
The upgrade cost is concentrated in registration. AddMediatR with a configuration callback is the documented entry point, and the README's list of what gets registered is long enough that a container which previously resolved IMediator by convention may behave differently after a version change. Any code that sets a licence key is also a version-sensitive surface, since the precedence order and the environment variable names are part of the documented contract.
The build files in the repository root include Build.ps1, BuildContracts.ps1, Push.ps1 and MediatR.slnx, and there is a separate BuildContracts.ps1, which is consistent with MediatR.Contracts being published as its own package. If you consume the contracts package, keep its version aligned with the main package rather than letting the two drift. The README does not document a rollback procedure or a compatibility matrix between major versions, so pinning an exact version in your project file is the only guarantee the documentation supports.
Editorial conclusion
Adopt MediatR when you want request and notification dispatch that is decoupled from the code calling it, and when a licence key is acceptable in your build and deployment pipeline. Skip it if a plain interface plus constructor injection already gives you the indirection you need, or if adding a paid dependency to a small service is not worth the paperwork. Before committing, verify three things against your own solution: that RegisterServicesFromAssemblyContaining actually scans the assembly your handlers live in, that the resolved licence key path (code, MEDIATR_LICENSE_KEY, then LUCKYPENNY_LICENSE_KEY) matches how your environment injects secrets, and that your container registrations for IMediator, ISender and IPublisher are not being overridden by a later call.
Frequently asked questions
What is MediatR in .NET?
It is an in-process mediator implementation for .NET, described in the README as "in-process messaging with no dependencies". It routes requests, commands, queries, notifications and events to handlers, with synchronous and async support.
How do I add MediatR in Program.cs?
Register it on the service collection with AddMediatR and an assembly to scan, for example services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<Startup>()). The README shows this form and an overload taking an explicit assembly.
How much does MediatR cost?
The README does not list prices. It states that you set a licence key in code via cfg.LicenseKey or Mediator.LicenseKey, or through the MEDIATR_LICENSE_KEY or LUCKYPENNY_LICENSE_KEY environment variables, and that keys are issued at MediatR.io.
Is MediatR really necessary?
The README presents it as a dispatch mechanism rather than a requirement. It removes direct references from callers to handler types, but if constructor injection already gives you that separation, the extra request type, handler class and registration may not buy anything.
How do I set the MediatR licence key?
Set cfg.LicenseKey inside the AddMediatR callback, or Mediator.LicenseKey when you are not using Microsoft.Extensions.DependencyInjection. If neither is set, MediatR falls back to the MEDIATR_LICENSE_KEY and LUCKYPENNY_LICENSE_KEY environment variables.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/luckypennysoftware-mediatr)