The fast in-memory message passing tool with zero-allocation for Unity and .NET. And the very thin layer that organize application datal-flow.
$ dotnet add package VitalRouterVitalRouter is a high-performance, zero-allocation in-memory messaging library for C#. It is specifically designed for environments where performance and decoupling are critical, such as Unity games or complex .NET applications.
By using simple attributes, you can implement asynchronous handlers, middleware (interceptors), and advanced sequence control. VitalRouter leverages Roslyn Source Generators to produce highly efficient code, promoting a clean, unidirectional control flow with minimal overhead.
Visit vitalrouter.hadashikick.jp to see the full documentation.
[Routes] and [Route] to define handlers.VitalRouter follows a simple messaging flow. A Publisher sends a Command to a Router, which then dispatches it through optional Interceptors to one or more Handlers.
---
config:
theme: dark
---
graph LR
Publisher[Publisher] -- PublishAsync --> Router[Router]
subgraph Pipeline
Router -- next --> Interceptor1[Interceptor A]
Interceptor1 -- next --> Interceptor2[Interceptor B]
end
Interceptor2 -- Invoke --> Handler[Handler/Presenter]
Commands are lightweight data structures representing an event or action.
// record structs are recommended for zero-allocation messaging
public readonly record struct MoveCommand(Vector3 Destination) : ICommand;
[!TIP] AOT/HybridCLR Note: While
record structis valid, ensure your AOT metadata is correctly generated for iOS/AOT environments if using tools like HybridCLR.
Use the [Routes] attribute on a partial class to receive commands.
[Routes]
public partial class PlayerPresenter
{
// Use ValueTask for pure .NET performance
[Route]
public void On(MoveCommand cmd)
{
Console.WriteLine($"Moving to {cmd.Destination}");
}
// Use UniTask for Unity-specific async handling
[Route]
public async UniTask On(SomeAsyncCommand cmd)
{
await DoSomethingAsync();
}
}
Connect your handler to a router and start sending commands.
var router = new Router();
var presenter = new PlayerPresenter();
// MapTo returns a Subscription (IDisposable)
using var subscription = presenter.MapTo(router);
// Publish a message
await router.PublishAsync(new MoveCommand(new Vector3(1, 0, 0)));
You can also subscribe using lambdas without using the source generator.
// Simple subscription
router.Subscribe<MoveCommand>(cmd => { /* ... */ });
// Async subscription with ordering
router.SubscribeAwait<MoveCommand>(async (cmd, ct) =>
{
await DoSomethingAsync();
}, CommandOrdering.Sequential);
// Inline interceptors (Filters)
router
.WithFilter<MoveCommand>(async (cmd, context, next) =>
{
Console.WriteLine("Before");
await next(cmd, context);
Console.WriteLine("After");
})
.Subscribe(cmd => { /* ... */ });
VitalRouter is highly optimized for Unity, especially when combined with UniTask.
When using MapTo in a MonoBehaviour, always bind the subscription to the object's lifecycle.
[Routes]
public partial class CharacterController : MonoBehaviour
{
private void Start()
{
// Bind the subscription to this GameObject's lifecycle
this.MapTo(Router.Default).AddTo(destroyCancellationToken);
}
[Route]
public void On(MoveCommand cmd)
{
transform.position = cmd.Destination;
}
}
[!IMPORTANT] Assembly Definition (.asmdef): You must reference
VitalRouterin your.asmdeffile for the Source Generator to process your[Routes]attributes.
UniTask is a fast async/await extension for Unity. VitalRouter actively supports UniTask. Requirements: UniTask >= 2.5.5
[!TIP] If UniTask is installed, the
VITALROUTER_UNITASK_INTEGRATIONflag is automatically turned on, executing optimized GC-free code paths.
| Package | Latest version |
|---|---|
VitalRouter | |
VitalRouter.Extensions.DependencyInjection | |
VitalRouter.R3 | |
VitalRouter.MRuby |
[!NOTE] Starting with version 2.0, distribution in Unity has been changed to NuGet.
VitalRouter packages in the NuGet window.Optional (UPM)
If you prefer UPM, you can install the assembly for Unity via Git URL:
https://github.com/hadashiA/VitalRouter.git?path=/src/VitalRouter.Unity/Assets/VitalRouter#2.2.0
Pipelining of async interceptors for published messages is possible. This is a general strong pattern for data exchange.
R3 is the next generation Reactive Extensions implementation in the C# world. VitalRouter supports the ability to work with R3.
Control command publishing via external MRuby scripts. Fiber in mruby and async/await in C# are fully integrated.

Based on large-scale production usage (e.g., HybridFrame):
record struct provides equality comparison and zero-allocation benefits..AddTo(destroyCancellationToken) or manual Dispose() to avoid memory leaks and ghost event handling.UniTask or UniTaskVoid as return types in Unity handlers to leverage optimized pooling. Use ValueTask for pure .NET projects.PublishContext for cross-cutting concerns (logging IDs, cancellation tokens, user permissions) rather than polluting your command structs.CommandOrdering.Sequential for UI animations or dialogue sequences to prevent race conditions.MIT
@hadashiA