Skip to content

lattice / orientation

Quick Start

Get up and running with lattice in minutes.

Install the umbrella package:

Terminal window
gleam add lattice_crdt

This gives you the core CRDT packages. See Installation for individual package options, including distributed presence.

GCounter is the simplest place to start: each replica can only increase its own contribution, and merging takes the per-replica maximum.

Save this as src/quick_start.gleam:

On narrow screens, scroll code blocks horizontally to read each full line.

import gleam/int
import gleam/io
import lattice_core/replica_id
import lattice_counters/g_counter
pub fn main() {
let assert Ok(counter_a) =
g_counter.new(replica_id.new("node-a"))
|> g_counter.increment(2)
let assert Ok(counter_b) =
g_counter.new(replica_id.new("node-b"))
|> g_counter.increment(3)
let merged = g_counter.merge(counter_a, counter_b)
merged
|> g_counter.value
|> int.to_string
|> io.println
}

Run the example from your project directory:

Terminal window
gleam run -m quick_start

Expected output:

5

Success: you now have a convergent counter: two replicas updated independently, then merged into the same combined value.

g_counter.increment returns Result and rejects negative deltas with Error(NegativeDelta(delta)). If you need a counter that can go down, use pn_counter from lattice_counters; both increment and decrement still take non-negative deltas because the underlying state is grow-only.

For incremental replication, counters also expose *_with_delta mutators that return Ok(#(new_state, delta)) or an error. See Delta-State Replication.

Open these when you are ready to move beyond the first convergent counter. Each recipe has a stable fragment link: LWW register and OR-Map.

Advanced recipeResolve ties deterministically with LWW registersChoose a value by timestamp, with replica IDs breaking equal-timestamp ties.

LWWRegister stores a value plus a timestamp. Newer timestamps win. If two replicas write at the same timestamp, lattice breaks the tie deterministically using the replica ID.

import lattice_core/replica_id
import lattice_registers/lww_register
pub fn main() {
let left = lww_register.new("apple", 7, replica_id.new("node-a"))
let right = lww_register.new("zebra", 7, replica_id.new("node-b"))
let merged = lww_register.merge(left, right)
lww_register.value(merged)
// -> "zebra" (node-b > node-a lexicographically)
}

lww_register.set only applies when the new timestamp is strictly greater than the current one.

Advanced recipeStore CRDT values inside an OR-MapTrack add-wins keys while merging a nested CRDT value for each key.

ORMap(a) tracks keys with add-wins semantics within a generation and stores a CRDT child at each key. CrdtSpec(a) determines its initial value. Re-adding a removed key starts a fresh generation; the newer generation wins over older content.

import lattice_core/replica_id
import lattice_counters/g_counter
import lattice_maps/crdt
import lattice_maps/or_map
fn add_points(value: crdt.Crdt(String), delta: Int) -> crdt.Crdt(String) {
case value {
crdt.CrdtGCounter(counter) -> {
let assert Ok(counter) = g_counter.increment(counter, delta)
crdt.CrdtGCounter(counter)
}
other -> other
}
}
pub fn main() {
let assert Ok(scoreboard_a) =
or_map.new(replica_id.new("node-a"), crdt.GCounterSpec)
|> or_map.update("alice", fn(value) { add_points(value, 2) })
let assert Ok(scoreboard_b) =
or_map.new(replica_id.new("node-b"), crdt.GCounterSpec)
|> or_map.update("alice", fn(value) { add_points(value, 3) })
let assert Ok(merged) = or_map.merge(scoreboard_a, scoreboard_b)
case or_map.get(merged, "alice") {
Ok(crdt.CrdtGCounter(counter)) -> g_counter.value(counter)
_ -> 0
}
// -> 5
}

or_map.update returns Error(TypeMismatch(...)) if the callback returns a different CRDT variant from the map's specification. The examples use known positive amounts; handle counter errors before updating a map when amounts come from external input.

For more detail, see the Counters guide, Registers guide, Sets guide, and Maps guide. For topic/key presence tracking, see the Presence guide.