# Consumer Group (/sdks/csharp/how-to/events-store/consumer-group)



## Overview [#overview]

A **consumer group** turns Events Store from a broadcast fan-out into a competing-consumers queue: subscribers sharing the same group split the stored events between them instead of each getting a copy of every event. Reach for this when a durable, ordered event log also needs to scale horizontally — a stream of order updates or audit records where one processor can't keep up, but each event still needs to be handled exactly once by the group as a whole.

It works by setting the same `Group` on the `EventStoreSubscription` passed to `SubscribeToEventsStoreAsync` for each subscriber, alongside a `StartPosition` such as `EventStoreStartPosition.StartFromFirst`. The broker load-balances deliveries across every active member sharing that group and channel; adding another subscriber with the same group name is all it takes to add capacity. &#x2A;*Gotchas:** the start position belongs to the group's shared read cursor, not to any one subscriber — members joining later pick up wherever the group already is, not from the beginning. Omitting `Group` (or using different group names) silently means broadcast instead of load balancing, with no error to warn you. Delivery is exactly-once per group, but a crashed member's in-flight event isn't automatically handed to another member — design processing to be safely restartable.

## Prerequisites [#prerequisites]

* KubeMQ server running on `localhost:50000`
* C# SDK installed (`dotnet add package KubeMQ.SDK.CSharp`)

## Code [#code]

```csharp title="Program.cs"
// KubeMQ .NET SDK — Events Store: Consumer Group
//
// This example subscribes to an event store channel using a consumer group.
// Multiple instances in the same group will load-balance messages between them.
//
// Prerequisites:
//   - KubeMQ server running on localhost:50000
//   - dotnet run

using KubeMQ.Sdk.Client;
using KubeMQ.Sdk.EventsStore;
using System.Text;

await using var client = new KubeMQClient(new KubeMQClientOptions
{
    Address = "localhost:50000",
    ClientId = "csharp-eventsstore-consumer-group-client",
});
await client.ConnectAsync();

var subscription = new EventStoreSubscription
{
    Channel = "csharp-eventsstore.consumer-group",
    Group = "my-consumer-group",
    StartPosition = EventStoreStartPosition.StartFromFirst,
};

Console.WriteLine("Subscribed with consumer group 'my-consumer-group'. Waiting for events...");
await foreach (var evt in client.SubscribeToEventsStoreAsync(subscription))
{
    Console.WriteLine($"[Seq {evt.Sequence}] {Encoding.UTF8.GetString(evt.Body.Span)}");
}

```

## How It Works [#how-it-works]

* Setting `Group = "my-consumer-group"` routes each stored event to exactly one subscriber in the group. Spin up multiple instances (different `ClientId`) to load-balance replay and live events across them.
* `StartFromFirst` means this subscriber will receive the full history of the channel from the beginning, followed by new events as they arrive.
* Omitting the group switches to broadcast: every subscriber receives every stored and new event independently.
* The `await foreach` with no cancellation token runs indefinitely — terminate with Ctrl+C or pass a `CancellationToken`.

## Related [#related]

* [Pattern overview](/learn/events-store/getting-started)
* [C# SDK Reference](/sdks/csharp/reference)
* [Persistent Pub/Sub](/sdks/csharp/tutorials/persistent-pubsub)
* [Cancel Subscription](/sdks/csharp/how-to/events-store/cancel-subscription)
