sleipnir

sleipnir

Mesh - Capability-based routing for Processes on the BEAM

Hello everyone,

We’d like to share Mesh, a new open-source Elixir library developed by the Eigr community.

Mesh was created as part of the work on Spawn, where we needed a reliable and scalable way to route messages to specific groups of processes across a cluster, with deterministic behavior and minimal coordination overhead.

During Spawn’s development, we evaluated existing solutions such as :pg, Horde, and ProcessHub. These are solid libraries and work very well for many use cases. However, for our specific requirements — especially around capability-based routing, deterministic ownership, and very large-scale clustering — none of them fit exactly what we needed. Rather than forcing a model that didn’t align with our constraints, we decided to design a small, focused abstraction that could serve as a foundation for Spawn and similar systems.

That abstraction became Mesh.

What Mesh is

Mesh is a library for managing virtual processes and routing messages to them based on capabilities, rather than direct PIDs or global names.

At a high level, Mesh provides:

  • Capability-based process registration

  • Deterministic routing using shards

  • Decoupling between callers and process location

  • A model where any node can invoke a virtual process, and the system resolves where it should run

Processes register themselves with one or more capabilities, and callers route messages by capability and key. Mesh handles shard ownership and node selection, allowing systems to scale without relying on global process registries.

Example usage

Registering a process with a capability:

Mesh.register_capabilities([:game, :chat])

Routing a message to a virtual process by capability and key:

{:ok, pid, response} = Mesh.call(%Mesh.Request{
  module: MyApp.GameActor,
  id: "player_123",
  payload: %{action: "move"},
  capability: :game
})

Mesh also exposes simple functions for understanding cluster state:

Mesh.nodes_for(:game)     #=> [:node1@host, :node2@host]
Mesh.all_capabilities()   #=> [:game, :chat, :payment]

These helpers return lists of nodes that support a given capability or all capabilities registered in the cluster

Under the hood, Mesh computes a shard from the routing key, determines the owner node for that shard and capability, and delivers the message to the appropriate process — locally or remotely — without the caller needing to know where that process lives.

This makes Mesh particularly useful for systems that need:

  • Logical actors

  • Deterministic placement

  • Clear separation between routing logic and business logic

Project status

Mesh is new and under active development. The API is intentionally small, and we expect it to evolve as we continue integrating it into Spawn and gather feedback from real-world usage.

We’re sharing it early because we believe the underlying ideas may be useful beyond our own projects, especially for people building distributed systems on the BEAM who need more control over routing semantics.

Links

Documentation:
https://hexdocs.pm/mesh/Mesh.html

Hex package:

Spawn:

https://github.com/eigr/spawn

GitHub repository:

https://github.com/eigr/mesh

Feedback, questions, and contributions are very welcome.

— Eigr community

First Post!

garrison

garrison

Seems cool.

Btw, this is not consistent hashing. It’s just regular hash sharding. There is no ring; it will catastrophically reshard if a node is added.

You should use rendezvous hashing anyway. That is, if you need to worry about resharding at all (I’m not sure you do).

Most Liked

garrison

garrison

tbh y’all need to chill this thread is kinda unhinged

It seems to me like you know what you’re doing and wrote a library that makes sense for your case, but when describing it in the readme you (understandably) tried to put it into very general terms. But because it’s very general everyone is just going to project their own experiences onto it instead.

In a similar situation I found that explicit examples help. The sidecar thing makes sense to me; consider adding it to the readme.

Asd

Asd

I’ve just reread my post, and it sounds a bit toxic. I want to make clear that given that this implementation is poor, it is a good start and the whole idea is not strange, but it is a classic problem which was solved several times by other authors from Elixir community and what you’re doing with Mesh is a good starting point to explore the problem space

My personal recommendation would be to

  1. Learn more about distributed systems. I would love to provide some books and resources that I personally find useful, but unfortunately very few of them are in English :frowning:
  2. Take a look at existing implementations, learn about their tradeoffs. For example, Horde library solves the similar problem, but it uses eventually consistent delta-CRDT merkle tree structure to (eventually) maintain the same version of the information about which processes belong to what groups. Other good example is ProcessHub which is, afaik, still in active development phase.
  3. Learn more about consistent hashing algorithms and their applicability. These algorithms are very interesting because there is an exotic mix of finite field algebra and some empirical observations of how distributed systems change their memberships
  4. Dont be afraid to ask questions. You can tag me in any thread or use the personal messages. I also provide mentorship and consulting services. But you can also just create topics on the forum. Discussions about distributed systems are especially welcome here

I am looking forward to seeing the new version of Mesh which would use some interesting distributed algorithm. Happy coding :grinning_cat:

sleipnir

sleipnir

Good catch — you’re right about the terminology.

Mesh currently uses deterministic hash-based sharding, not classic consistent hashing with a ring. Shards are fixed and process are mapped to shards via phash2/2.

That said, this is a deliberate design choice aligned with our use case. Mesh routes messages to virtual processes, not persistent data partitions. Actors are ephemeral, lazily created, and can be safely recreated elsewhere. As a result, minimizing “resharding cost” is not a primary concern for us.

Nodes joining or leaving do not change shard assignment — only shard ownership. There is no data migration involved, and no state is coupled to shard placement.

Rendezvous hashing is a great tool and could be explored in the future, but for now the current approach gives us simpler reasoning, O(1) routing decisions, and predictable behavior, which fits well with Mesh and Spawn’s actor model.

Still, thanks for pointing this out — we should probably avoid calling it “consistent hashing” in the docs and be more precise about the terminology. We’re always open to evolving the routing strategy as new requirements emerge.

Where Next?

Trending in Announcing Top

bluzky
You may know https://ui.shadcn.com/, a UI component library for React. I really love it’s design style and components. I’ve built some co...
385 14863 120
New
GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
shahryarjb
The Chelekom project is a library of Phoenix and LiveView components generated via Mix tasks to fit developer needs seamlessly. One of i...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
kip
Following on from my CLDR lbraries I started work on Unicode transforms. But like everything related to CLDR there is a lot of yak-shavin...
New
anuaralfetahe
Hello Published a new library - ProcessHub! ProcessHub is a library designed to manage process distribution within the Elixir cluster. ...
New
kip
Localize is the next generation localisation library for Elixir. Think of it as ex_cldr version 3.0. The first version will be released ...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
kip
Localize is the next generation localisation library for Elixir. Think of it as ex_cldr version 3.0. The first version will be released ...
New
webofbits
Squid Mesh is an open source workflow automation runtime for Elixir applications. It is aimed at Phoenix and OTP apps that want to defin...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
kip
In 2021 I started a new library called Tempo with the objective of modelling time as a set of intervals - not as instants. In 2022 I gave...
New

We're in Beta

About us Mission Statement