Architecture #

A few properties set Matrix apart from the typical client-server chat you know:

  • Event-sourced. Every message, reaction, edit, membership change, avatar update and topic change is an event. Rooms are an ordered log of events, not a mutable table of "current state". That's why you can replay history exactly, walk back in time to any point, and bridge to external networks cleanly — everything is just events.
  • Eventually consistent. When federated servers disagree about the order of events (network partitions, slow links), Matrix applies a deterministic state resolution algorithm to agree on a canonical current state without blocking writes. It trades strong consistency for availability — conversations keep flowing even when half the network is unreachable.
  • DAG, not linear log. Events don't form a single chain; they form a Merkle-DAG where each event references its predecessors. This handles concurrent writes naturally: two people sending a message at the same time across different homeservers each produce an event that points at the previous shared state, and both get woven into the history.
  • Extensible. The event types are open. Official ones (m.room.message, m.room.member, m.reaction…) cover the everyday case; custom types let you build polls, maps, CRDTs, collaborative editors, game state, IoT telemetry — anything that wants a decentralized replicated log with auth.
  • Transport-agnostic cryptography. E2EE is part of the protocol, not an afterthought. Every participating server sees only ciphertext for encrypted rooms. See Encryption for details.
  • HTTP-native. All APIs are JSON over HTTPS. No custom binary format, no proprietary TLS extension — debuggable with curl.

The architecture in one diagram #

                    Federation (Server-Server API, HTTPS+JSON)
                    ┌─────────────────────────────────────┐
                    │                                     │
    ┌───────────┐   │    ┌───────────┐       ┌──────────┐ │    ┌───────────┐
    │ Element   │──┼──▶ │ your.     │ ◀───▶ │ matrix.  │◀┼─── │ FluffyChat│
    │ (web)     │   │    │ meldry.   │       │ org      │ │    │ (mobile)  │
    │           │◀─┼─── │ com       │       │          │ │─── │           │
    └───────────┘   │    └───────────┘       └──────────┘ │    └───────────┘
                    │          ▲                    ▲     │
                    │          │                    │     │
                    │          ▼                    ▼     │
                    │    ┌───────────┐       ┌──────────┐ │
                    │    │ bridges,  │       │ appsvcs, │ │
                    │    │ appsvcs   │       │ bots     │ │
                    │    └───────────┘       └──────────┘ │
                    └─────────────────────────────────────┘
     Client-Server API                   Server-Server API
     (what Element talks)                (what homeservers talk
                                          to each other)
  • Clients talk the Client-Server API: HTTPS + JSON, defined in the spec. Element, FluffyChat, Nheko, Cinny, your own bot — all of them hit the same endpoints on your homeserver.
  • Homeservers talk the Server-Server API (federation) to each other over HTTPS + signed JSON. This is how a user on your-name.meldry.com can chat with a user on matrix.org without a middleman.
  • Bridges and appservices attach to a homeserver and extend it with virtual users and rooms (see Bridges and Appservices).

You pick the client, Meldry runs the homeserver, the protocol does the rest.

Communication principles #

The Client-Server API #

When Element or any client talks to your homeserver, it does one of four things:

  1. /sync — a long-poll that returns everything new since the last request: new events in rooms, new invites, presence changes, to-device messages. Clients keep one /sync open at all times; the server holds it open for up to 30 seconds and then returns whatever arrived.
  2. PUT /rooms/{id}/send/{event_type}/{txn_id} — sends a new event (a message, a reaction, a redaction). The txn_id makes sends idempotent so retries don't duplicate.
  3. State queries — fetch the current room state, member list, power levels.
  4. Media uploads / downloads — binary blobs travel over a separate content-repository endpoint, keyed by a mxc:// URI.

Everything is authenticated with a bearer access token obtained at login. See the Matrix client-server spec for the full API.

The Server-Server API (federation) #

When your homeserver needs to send a message into a room that has members on another server, it:

  1. Signs the event with the server's Ed25519 key.
  2. Sends it over HTTPS to the remote server's federation endpoint.
  3. The remote server verifies the signature against the sender-server's public key (fetched over HTTPS with its own key verification step).
  4. The remote server applies the event to its local copy of the room state.

The remote server doesn't trust the sender blindly — it verifies every event's signature and checks that the event's "auth chain" (the sequence of auth events that justify why this event is allowed at all) is valid according to the room's power-level rules.

If two servers add events concurrently, the state resolution algorithm picks a canonical ordering based on the events' auth_events and a deterministic tie-breaker. Both servers end up with the same final state.

Event graph (DAG) #

Every event in a room contains a prev_events field listing the hashes of events it was sent in response to. With many participants across many servers, prev_events can point at multiple predecessors, forming a directed acyclic graph. Clients walk the DAG backwards to show you history; servers use it to detect and heal forks when federation catches up after a partition.

Rooms and spaces #

Rooms #

A room is a shared, replicated event log with auth rules. Every room has:

  • A permanent internal ID !abc123:server
  • Zero or more human-friendly aliases #general:server
  • A power-level graph — an integer per user plus defaults, deciding who can send messages, invite, kick, ban, redact, change topic, upgrade, etc. PL 0 = ordinary member, PL 50 = moderator, PL 100 = admin (these are conventions, not fixed).
  • Optional end-to-end encryption
  • A history visibility setting — whether new joiners see only messages after they joined, all history, or whatever the room owner picks.

Rooms can be public (listed in the homeserver's directory) or private (invite-only). They're not scoped to a homeserver — a room that originated on matrix.org can have members on your-name.meldry.com, on kde.org, and on element.io all simultaneously, and every homeserver replicates its own copy of the events.

Spaces #

A space is a special kind of room whose "members" are other rooms and other spaces. Spaces are Matrix's answer to "I want a Slack workspace" or "I want a Discord server" — they group related rooms into a browseable hierarchy. You can nest spaces, mark some rooms as "suggested", and selectively share parts of a space with outsiders.

Under the hood a space is just a room with a specific room type (m.space) and m.space.child state events pointing at its children.

What's next #

  • Identity — how accounts, sigils and device IDs work
  • Encryption — the E2EE layer built on top of this architecture
  • Ecosystem — implementations that speak this protocol today