A lightweight framework to help creating CQRS and Eventsourcing applications in C#
C#
1,119
468 commits
updated Oct 5, 2026
CQRSlite is a small framework for building applications with CQRS and event sourcing in C#. It gives you the building blocks (aggregates, a unit of work, repositories, a message router, snapshots and caching) and stays out of the way of everything else. Every part is behind an interface, so any of it can be replaced.
CQRSlite started as a CQRS sample project Greg Young and Gaute Magnussen made in 2010, which lives on at gregoryyoung/m-r.
dotnet add package CqrsLite
CQRSlite targets .NET 10 and .NET Standard 2.0, so it also runs on .NET Framework 4.6.2 and later. Its only dependency is Microsoft.Extensions.Caching.Memory. You provide the event store for your database; see the event store guide.
Business rules live in aggregates, which record events instead of changing state directly:
public class InventoryItem : AggregateRoot
{
// ...
private void Apply(ItemsCheckedInToInventory e)
{
_count += e.Count;
}
private void Apply(ItemsRemovedFromInventory e)
{
_count -= e.Count;
}
// ...
public void Remove(int count)
{
if (count <= 0) throw new InvalidOperationException("cant remove negative count from inventory");
if (count > _count) throw new InvalidOperationException($"cant remove {count} items, only {_count} in stock");
ApplyChange(new ItemsRemovedFromInventory(Id, count));
}
// ...
}
Command handlers load an aggregate through the session, call it, and commit:
public async Task Handle(RemoveItemsFromInventory message, CancellationToken token)
{
var item = await _session.Get<InventoryItem>(message.Id, message.ExpectedVersion, token);
item.Remove(message.Count);
await _session.Commit(token);
}
The rest of the application sends commands and queries through the router:
await _commandSender.Send(new RemoveItemsFromInventory(id, number, version), cancellationToken);
These articles by others were written for older versions of CQRSlite, so details have changed, but the ideas still hold:
You need the .NET 10 SDK.
dotnet build
dotnet test
The docs are checked against the code: python3 .github/scripts/check_docs.py verifies that code snippets in the docs still match the files they come from, and that links between pages work. CI runs it on every push.
Copyright 2020 Gaute Magnussen
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
Overall
Maintained
Code review
NuGet
Latest release
Releases this year
906 followers · starred Nov 2015
62 followers · starred Jul 2017
660 followers · starred Jul 2017
26 followers · starred Oct 2018
A lightweight framework to help creating CQRS and Eventsourcing applications in C#
C#
1,119
468 commits
updated Oct 5, 2026
CQRSlite is a small framework for building applications with CQRS and event sourcing in C#. It gives you the building blocks (aggregates, a unit of work, repositories, a message router, snapshots and caching) and stays out of the way of everything else. Every part is behind an interface, so any of it can be replaced.
CQRSlite started as a CQRS sample project Greg Young and Gaute Magnussen made in 2010, which lives on at gregoryyoung/m-r.
dotnet add package CqrsLite
CQRSlite targets .NET 10 and .NET Standard 2.0, so it also runs on .NET Framework 4.6.2 and later. Its only dependency is Microsoft.Extensions.Caching.Memory. You provide the event store for your database; see the event store guide.
Business rules live in aggregates, which record events instead of changing state directly:
public class InventoryItem : AggregateRoot
{
// ...
private void Apply(ItemsCheckedInToInventory e)
{
_count += e.Count;
}
private void Apply(ItemsRemovedFromInventory e)
{
_count -= e.Count;
}
// ...
public void Remove(int count)
{
if (count <= 0) throw new InvalidOperationException("cant remove negative count from inventory");
if (count > _count) throw new InvalidOperationException($"cant remove {count} items, only {_count} in stock");
ApplyChange(new ItemsRemovedFromInventory(Id, count));
}
// ...
}
Command handlers load an aggregate through the session, call it, and commit:
public async Task Handle(RemoveItemsFromInventory message, CancellationToken token)
{
var item = await _session.Get<InventoryItem>(message.Id, message.ExpectedVersion, token);
item.Remove(message.Count);
await _session.Commit(token);
}
The rest of the application sends commands and queries through the router:
await _commandSender.Send(new RemoveItemsFromInventory(id, number, version), cancellationToken);
These articles by others were written for older versions of CQRSlite, so details have changed, but the ideas still hold:
You need the .NET 10 SDK.
dotnet build
dotnet test
The docs are checked against the code: python3 .github/scripts/check_docs.py verifies that code snippets in the docs still match the files they come from, and that links between pages work. CI runs it on every push.
Copyright 2020 Gaute Magnussen
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
Overall
Maintained
Code review
NuGet
Latest release
Releases this year
906 followers · starred Nov 2015
62 followers · starred Jul 2017
660 followers · starred Jul 2017
26 followers · starred Oct 2018