Skip to content
← All writing

Building a chat app for when the internet disappears

ReliefLink began with an uncomfortable question: what does communication software look like when the cloud is gone?

March 24, 2026 · 8 min read
Emergency responders coordinating over a peer-to-peer mesh network without central infrastructure.

Start by removing the cloud

Most chat applications begin with an API, a database, and a reliable route to both. ReliefLink began by deleting that assumption.

The project was built around disaster-hit areas where cellular and internet infrastructure may be unavailable. If two devices can still reach the same local network, they should be able to discover each other and exchange messages without waiting for a central server.

That sounds like a networking problem. It is also a product-design problem: every hidden dependency becomes a failure mode when the environment is already difficult.

Offline-first is not a cache strategy here. It is the condition the product has to survive.

Discovery without a directory

I used Go and libp2p for the backend. Multicast DNS (mDNS) lets peers announce and discover a shared service on a local network, which means there is no directory server to configure before people can communicate.

Each node joins with a shared discovery string. When another ReliefLink peer appears on the LAN, the application can learn its identity and establish a direct connection.

service := mdns.NewMdnsService(
    host,
    "relieflink-local",
    &peerNotifee{host: host},
)

if err := service.Start(); err != nil {
    log.Fatal(err)
}

The first successful discovery felt more meaningful than a normal “hello world.” Two independent processes had found each other without a URL, account, or cloud dashboard sitting between them.

Rooms are topics, not database rows

For group communication, I used libp2p PubSub. A room name maps to a topic. Peers subscribe to that topic and publish messages directly to the group.

The command-line application accepts configurable flags for port, room, and identity. That made it easy to run several nodes locally and test arrival order, disconnects, and room isolation without constantly editing source code.

The architecture stayed intentionally small:

  • mDNS discovers nearby nodes;
  • libp2p establishes peer identities and connections;
  • PubSub distributes room messages;
  • a local HTTP API bridges the Go node to a React interface;
  • and logs.txt keeps a durable local record.

There is no component whose job is “be the internet.”

The browser still needed a bridge

The React frontend could not talk to libp2p in the same way as the Go process, so I exposed a local HTTP API behind an --enable-http flag. The browser talks to its own local node; the node handles peer discovery and message propagation.

That boundary turned out to be useful. The networking layer stays testable from the CLI, while the interface can evolve without owning peer-to-peer concerns.

It also taught me to be careful with the word “decentralized.” A system is not automatically resilient because it uses peer-to-peer transport. Identity, duplicate messages, reconnection, storage, and conflicting state still need explicit answers.

Logging is a feature when connectivity is uncertain

Every received message is written locally. The log is simple, but simplicity is an advantage in an emergency tool. When connectivity flickers, a user should not lose the conversation just because a peer temporarily vanished.

If I continued the project, I would add signed messages, clearer delivery states, and a synchronization protocol for peers that reconnect after being separated. I would also test across real routers and crowded networks; a laptop demo cannot reproduce the conditions the system is intended for.

What ReliefLink changed in my thinking

Building ReliefLink made me notice how many products quietly assume perfect infrastructure. Login, push notifications, cloud storage, analytics, and remote configuration are convenient until each one becomes a prerequisite.

The project taught me to ask a different first question: what is the smallest useful thing two nearby devices can do entirely on their own?

For ReliefLink, the answer was modest—find one another, join a room, exchange a message, and keep a local record. But when the internet disappears, modest and dependable beats impressive and unreachable.