Skip to content

Cellular, not flood

Every popular LoRa mesh is mesh-egalitarian: all nodes are peers, and messages propagate by flooding — each node rebroadcasts what it heard, with dedup and hop limits keeping the storm survivable. It’s a beautiful model for its design point: no infrastructure, no roles, works anywhere two radios can hear each other. Meshtastic’s “managed flood” and MeshCore’s flood-discovery-then-direct-paths are both serious, tuned implementations of it.

But flooding has a growth law, and it’s the wrong one for chat at scale. In a flood, a busy channel costs airtime proportional to listeners × hops — every message occupies the shared spectrum once per rebroadcasting node. Past a few hundred nodes on a channel, the network spends its airtime budget repeating itself. This isn’t an implementation flaw; it’s what “everyone relays everything” means.

LoRa Relay Chat borrows the architecture the telephone industry converged on: cells. Routers form a backbone; clients attach to a router with a signed HELLO/WELCOME handshake (a real authenticated key agreement, X25519 + nonces, over LoRa) the way a phone attaches to a tower. After that:

  • A channel message goes up to your router once, and down from each router that has members in that channel once. Fan-out cost is per access network, not per listener.
  • Routers federate — over TCP when the internet is available, over RF lanes when it isn’t. A packet that crossed the internet is re-emitted on radio only at the destination’s access router. (No MQTT broker. Peer links, operator-pinned.)
  • Flooding still exists — for discovery only, TTL-capped at 3 and rate-limited. Steady-state traffic never floods.

Here’s the part that matters more than the airtime math. Because a router sequences its channel traffic — every message gets a per-channel, per-router sequence number — the stream becomes auditable for holes. A missed message isn’t silently gone the way it is in a flood; it’s a detectable gap, and one mechanism (ranged backfill requests) heals all of these identically:

  • you were out of range for an hour → gap → backfilled;
  • your node rebooted → gap from the stored cursor → backfilled;
  • you just joined a channel → your cursor is “before everything” → scrollback appears;
  • two routers netsplit and rejoin → per-stream max-sequence vectors disagree → ranged backfill reconciles them.

The network behaves like a write-ahead log, not a best-effort shout. IRC semantics (netsplits, rejoins, channel history on join) turn out to map onto this almost embarrassingly well — which is part of why the IRC gateway isn’t a gimmick but a natural interface to the thing the protocol actually builds.

Infrastructure has to exist: somebody sites and runs routers, and a lone pair of radios with no router is a degenerate network. Roles make the system more complex to operate than a flood mesh where every node ships identical firmware. A compromised or malicious router is inside the trust boundary for its own cell — a residual the docs carry openly rather than hand-waving. And a total-order guarantee across federated routers does not exist (physics; display order is origin-timestamp merged). The full trade-sheet, including the scaling walls the design does not solve — directory growth, single-thread daemon, airtime in a dense cell — is in the deep dive, which includes a section titled “why not a million users” precisely because that’s the first question worth distrusting in any mesh pitch.

Deeper reading: Routing & federation, the comparison page.