---
title: "G-Set (Grow-Only Set)"
url: "https://nsta1.github.io/Orleans.Lattice/docs/crdt/gset.html"
source: "https://github.com/NSTA1/Orleans.Lattice/blob/release/9.9/docs/crdt/gset.md"
documents: "Orleans.Lattice 9.9.0 (release line 9.9)"
built: "2026-10-04"
all-pages: "https://nsta1.github.io/Orleans.Lattice/llms.txt"
bundle: "https://nsta1.github.io/Orleans.Lattice/docs/crdt/llms-full.txt"
---
# G-Set (Grow-Only Set)

Part of the [CRDTs documentation](readme.md).

`tree.GSet(key)` -> `GSetAccessor`, merge mode `LatticeMergeMode.GSet`.

## Semantics

A **G-Set** is a set that only ever **grows**: elements can be added but never
removed. Elements are opaque `byte[]` compared by content. The merge is plain
**set union**, which is trivially commutative, associative, and idempotent, so
concurrent active-active adds from any number of clusters all survive
convergence and a re-delivered add is harmless.

Because it carries no dots and no tombstones, a G-Set is the **minimal** set
primitive - the smallest, cheapest choice for append-only workloads such as tag
sets, seen-ids, or an accumulating audience. When you need to remove elements,
reach for the add-wins [OR-Set](orset.md) or the remove-wins [RW-Set](rwset.md)
instead.

## Behaviour

Figure: Two concurrent G-Set adds meeting at their join. An order diagram shaped like a diamond, ordered by set inclusion. At the bottom is the empty set. Cluster A adds alice, reaching {alice}. Cluster B, at the same time, adds bob, reaching {bob}. Neither set contains the other. Merging takes the union, so both paths rise to the same top state, {alice, bob}.

Both clusters hold {alice, bob}. Union keeps every add, so no concurrent add is lost.

Merge is plain set union, which is commutative, associative, and idempotent.

```mermaid
sequenceDiagram
    participant A as Cluster A
    participant B as Cluster B
    A->>A: Add("alice")
    B->>B: Add("bob")
    A-->>B: merge ships {alice}
    B-->>A: merge ships {bob}
    Note over A,B: merge is set union
    Note over A,B: converged = {alice, bob}
```

## Example

```csharp verify
var seen = tree.GSet("campaign:autumn:reached");

// Two clusters add members concurrently; union keeps both.
await seen.AddAsync(Encoding.UTF8.GetBytes("alice"), cancellationToken);
await seen.AddAsync(Encoding.UTF8.GetBytes("bob"), cancellationToken);

bool reachedAlice = await seen.ContainsAsync(Encoding.UTF8.GetBytes("alice"), cancellationToken);
IReadOnlyList<byte[]> everyone = await seen.ToListAsync(cancellationToken);
```

See also: the add-wins [OR-Set](orset.md), the remove-wins [RW-Set](rwset.md),
and the [CRDT overview](readme.md).
