maelstrom-rs
maelstrom
Rust

The Matrix homeserver for serious scale. Clusterable, highly available, horizontally scalable.

Last updated Jul 2, 2026
258
Stars
19
Forks
105
Issues
+1
Stars/day
Attention Score
55
Language breakdown
Rust 96.0%
SurrealQL 1.9%
Shell 0.8%
CSS 0.5%
Makefile 0.4%
HTML 0.3%
โ–ธ Files click to expand
README

Maelstrom

The open-source, enterprise-scale Matrix homeserver.

Maelstrom is the only open-source Matrix homeserver built for horizontal scaling. It is a from-scratch Rust implementation with a stateless application layer, distributed graph storage via SurrealDB + TiKV, and true multi-instance clustering โ€” no worker model, no per-process GIL limits, no single-database bottleneck.

General discussion: #maelstrom-server:matrix.org

Why Maelstrom

Today's Matrix scaling options are limited:

  • Synapse (85% market share) scales via Python worker processes, each limited to one CPU core. At ~40 events/second, 25% of CPU is overhead before real work begins. Element's own engineering team calls this a hard ceiling โ€” and their solution, Synapse Pro, is proprietary and closed-source.
  • Conduit/Continuwuity (Rust) are fast on a single machine but use embedded RocksDB with no clustering capability.
  • Dendrite (Go) is in maintenance mode with no production-ready horizontal scaling.
There is no open-source Matrix homeserver that offers simple horizontal scaling for large deployments. Maelstrom fills that gap:
  • True horizontal scaling -- stateless Axum instances behind a load balancer, with chitchat gossip for cross-node ephemeral state. Scale by adding nodes. No worker types to configure, no process-specific routing, no external message broker.
  • Distributed storage -- SurrealDB on TiKV provides automatic sharding, replication, and ACID transactions across a cluster. No single-PostgreSQL bottleneck.
  • Rust performance -- no GIL, no garbage collector. A single instance handles what Synapse needs multiple workers for.
  • Full Matrix 2.0+ -- sliding sync, threads, reactions, spaces, E2EE, federation with Synapse/Dendrite/Conduit.
  • Built-in admin -- web dashboard and JSON API for user, room, media, and federation management. Prometheus metrics. Runtime-configurable media retention.
  • Graph-native -- the Matrix event DAG, room membership, and event relations (threads, reactions, edits) are modeled as SurrealDB graph edges, not flat tables with string foreign keys.

Project Status

Alpha -- under active development. Core functionality works. Not yet recommended for production deployments carrying real user data.

Complement Test Results (2026-04-10)

343+ / 538 tests passing (63.8%+) ยท 107 internal tests ยท zero clippy warnings

| Category | Pass | Total | Rate | |----------|------|-------|------| | Registration | 25 | 25 | 100% | | Login/Auth | 29 | 29 | 100% | | Profile | 15 | 15 | 100% | | Rooms | 73 | 83 | 88% | | Keys/E2EE | 25 | 34 | 74% | | Receipts | 2 | 3 | 67% | | Presence | 2 | 3 | 67% | | Messages | 32 | 51 | 63% | | Other | 26 | 42 | 62% | | Account | 6 | 10 | 60% | | Members | 30 | 50 | 60% | | Push | 4 | 7 | 57% | | Federation | 1 | 2 | 50% | | Typing | 2 | 4 | 50% | | Search | 3 | 7 | 43% | | Sync | 35 | 88 | 40% | | State | 22 | 67 | 33% | | Media | 1 | 5 | 20% | | Relations | 2 | 13 | 15% |

Solid foundations: Registration, login/auth, profiles, room creation, E2EE keys, receipts, and presence at or near 100%.

Actively working on: Federation (device lists, backfill), sync edge cases, relations, state resolution.

Quick Start

Docker (recommended)

git clone https://github.com/maelstrom-rs/maelstrom.git && cd maelstrom

Start backing services (SurrealDB + RustFS media storage)

docker compose -f docker-compose.dev.yml up -d

Copy and edit configuration

cp config/example.toml config/local.toml

Edit servername, bindaddress, and credentials as needed

Build and run

cargo build --release ./target/release/maelstrom

Maelstrom listens on port 8008 by default. Point your Matrix client at http://your-server:8008.

First Login

The first user to register becomes the server administrator automatically. Alternatively, set admin_user in your config to bootstrap an admin account on startup:

[server]
admin_user = "admin"

Configuration

All configuration lives in a single TOML file. Set MAELSTROM_CONFIG to override the default path (config/local.toml).

See config/example.toml for all options with comments.

[server]
bind_address = "0.0.0.0:8008"
server_name = "example.com"          # Your domain โ€” appears in user IDs (@user:example.com)
publicbaseurl = "https://example.com"

[database] endpoint = "ws://localhost:8000" # SurrealDB connection namespace = "maelstrom" database = "maelstrom" username = "root" password = "change-me"

[media] # Optional โ€” omit to disable media uploads endpoint = "http://localhost:9000" # RustFS / S3-compatible storage bucket = "maelstrom-media" access_key = "maelstrom" secret_key = "change-me" region = "us-east-1" maxagedays = 90 # 0 = keep forever sweepintervalsecs = 3600

[cluster] # Optional โ€” omit for single-node listen_addr = "0.0.0.0:7280" # UDP address for gossip protocol seed_nodes = ["node2:7280"] # Peers to bootstrap cluster from cluster_id = "maelstrom" # Nodes with different IDs ignore each other

Deployment Modes

Single Node

For personal use, small teams, or evaluation. One Maelstrom process with SurrealDB using file-based storage. No [cluster] config needed.

| Service | Purpose | Default Port | |---------|---------|-------------| | Maelstrom | Homeserver | 8008 | | SurrealDB | Database (SurrealKV file storage) | 8000 | | RustFS | Media storage (optional) | 9000 |

docker compose -f docker-compose.dev.yml up -d

Cluster

For production and high availability. Multiple Maelstrom instances behind a load balancer. SurrealDB backed by TiKV for distributed storage. Ephemeral state (typing indicators, presence) is synchronized across nodes via the chitchat gossip protocol over UDP โ€” no external message broker required.

| Service | Purpose | Default Port | |---------|---------|-------------| | Maelstrom (N instances) | Homeserver | 8008, 7280 (gossip) | | SurrealDB | Database (TiKV backend) | 8000 | | TiKV (3+ nodes) | Distributed storage | 20160 | | PD | TiKV Placement Driver | 2379 | | RustFS | Media storage | 9000 |

# Start the full stack (SurrealDB + TiKV + RustFS)
docker compose up -d

Add a [cluster] section to each node's config:

# Node 1 (maelstrom-1)
[cluster]
listen_addr = "0.0.0.0:7280"
seed_nodes = ["maelstrom-2:7280"]

Node 2 (maelstrom-2)

[cluster] listen_addr = "0.0.0.0:7280" seed_nodes = ["maelstrom-1:7280"]

Node 3+ only needs one seed โ€” learns the rest via gossip

[cluster] listen_addr = "0.0.0.0:7280" seed_nodes = ["maelstrom-1:7280"]

In Kubernetes, use a headless service as the seed โ€” chitchat resolves hostnames, so a single DNS entry returning all pod IPs works for automatic discovery.

Scale horizontally by running additional instances pointed at the same SurrealDB. All instances share one homeserver identity.

Administration

Admin Dashboard

Access the web dashboard at /_maelstrom/admin/ (requires an admin account).

Admin API

All admin operations are available as JSON endpoints under /_maelstrom/admin/v1/. Authenticate with a Bearer token from an admin user account.

| Endpoint | Description | |----------|-------------| | GET /server/info | Version, uptime, memory, database status | | GET /server/health | Detailed service health | | GET /metrics | Prometheus metrics (uptime, memory, DB status) | | GET /users/{userId} | User details, devices, room count | | POST /users/{userId}/deactivate | Deactivate account | | POST /users/{userId}/reactivate | Reactivate account | | POST /users/{userId}/reset-password | Reset password | | PUT /users/{userId}/admin | Grant admin | | DELETE /users/{userId}/admin | Revoke admin | | GET /rooms | List rooms | | GET /rooms/{roomId} | Room details and members | | POST /rooms/{roomId}/shutdown | Remove all members | | GET /media/user/{userId} | User's media files | | POST /media/{server}/{mediaId}/quarantine | Quarantine media | | GET /media/retention | View retention policy | | PUT /media/retention | Update retention policy at runtime | | POST /media/retention/sweep | Trigger immediate retention sweep | | GET /federation/stats | Federation status | | GET /reports | Abuse reports |

Health Checks

For load balancer and Kubernetes probe configuration:

| Endpoint | Purpose | Checks | |----------|---------|--------| | GET /_health/live | Liveness probe | Process is running | | GET /_health/ready | Readiness probe | Database connected |

Monitoring

Prometheus metrics are available at GET /_maelstrom/admin/v1/metrics (admin auth required):

maelstromuptimeseconds
maelstrommemoryused_bytes
maelstrommemorytotal_bytes
maelstromdatabaseup

Media Retention

Media retention can be configured in the TOML file or changed at runtime via the admin API:

# View current policy
curl -H "Authorization: Bearer $TOKEN" http://localhost:8008/_maelstrom/admin/v1/media/retention

Set 90-day retention

curl -X PUT -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"maxagedays": 90}' \ http://localhost:8008/_maelstrom/admin/v1/media/retention

Run an immediate cleanup

curl -X POST -H "Authorization: Bearer $TOKEN" \ http://localhost:8008/_maelstrom/admin/v1/media/retention/sweep

Federation

Federation is enabled automatically. Maelstrom generates an Ed25519 signing key on first startup and persists it in the database. Other servers can fetch your keys at /_matrix/key/v2/server.

For federation to work, your server must be reachable from the internet. Configure DNS:

  • Set an SRV record: matrix-fed.tcp.example.com โ†’ your-server:8448
  • Or serve .well-known/matrix/server returning {"m.server": "matrix.example.com:8448"}
  • Or run on port 8448 with your server_name resolving to your IP

Logging

Maelstrom uses structured logging. Set the log level via the RUST_LOG environment variable:

RUST_LOG=info ./maelstrom                    # Normal operation
RUST_LOG=debug ./maelstrom                   # Verbose
RUST_LOG=maelstrom=debug,surrealdb=warn ./maelstrom  # Debug Maelstrom, quiet SurrealDB

Architecture

| Layer | Technology | |-------|-----------| | Runtime | Rust + Tokio + Axum | | Database | SurrealDB v3 (graph model) | | Media | RustFS (S3-compatible) | | Ephemeral state | In-memory (DashMap) + chitchat gossip for clustering | | Admin dashboard | Askama SSR + Datastar | | Testing | Complement (Matrix spec conformance) |

All data is stored in SurrealDB using its graph model:

  • Events stored with DAG edges (event --prevevent--> event, event --authevent--> event)
  • Membership as graph relations (user --member_of--> room)
  • Reactions, threads, edits as graph relations (event --relates_to--> event)
Ephemeral data (typing indicators, presence) lives in-memory using lock-free DashMap structures. In cluster mode, the chitchat Scuttlebutt gossip protocol propagates ephemeral state across nodes over UDP with automatic TTL-based expiry โ€” no external message broker needed.

Building from Source

Requires Rust 1.85+ (2024 edition).

cargo build --release

The binary is at target/release/maelstrom. It is fully self-contained โ€” no runtime dependencies beyond libc.

Running Tests

# Unit and integration tests
cargo test

Matrix spec conformance (requires Docker + Go)

make complement

License

Licensed under Apache License, Version 2.0 or MIT License at your option.

๐Ÿ”— More in this category

ยฉ 2026 GitRepoTrend ยท maelstrom-rs/maelstrom ยท Updated daily from GitHub