Library / SDK
ruma/ruma avatar
ruma/ruma

ruma: the Rust crate set behind Matrix clients, servers and bridges

A set of Rust crates for interacting with the Matrix chat network.

742 stars205 forksRustMIT

At a glance

What is it?
Ruma is a set of Rust crates for the Matrix chat network, and it is deliberately not a client. It is the layer where Matrix events, identifiers, federation endpoints and signatures become Rust types, and the project draws a clear line between what it provides and what matrix-rust-sdk builds on top of it. The version numbers move independently across a dozen crates, and the room version rules are strict in a way that will surprise you.
Who is it for?
Adopt Ruma if you are writing a homeserver, a bridge or any software that speaks the Matrix protocol in Rust, because modelling the event and endpoint types by hand is a large and error-prone job. Do not adopt it as a ready-made client, since state storage and end-to-end encryption live in matrix-rust-sdk, and check your room versions before you rely on older ones.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Ruma is, and the three projects it deliberately is not

Ruma is a set of Rust crates for interacting with the Matrix chat network, and the way it describes itself, your home in Matrix, is a clue about its scope. It is the layer where the protocol becomes Rust types.

The README is unusually clear about where it stops. If you want to build a Matrix client or a bot, you should look at matrix-rust-sdk, which builds on Ruma and includes handling of state storage, end-to-end encryption and many other useful things. For homeservers, bridges and harder-to-categorize software that works with Matrix, you are at the right place with Ruma itself.

And then there is a third thing: a low level Matrix client lives in the separate ruma-client repository, with a small number of examples in the ruma-examples repository.

So there are three layers, and picking the wrong one is the most common mistake. Ruma is the type and protocol layer. matrix-rust-sdk is the application layer for clients and bots, with the hard parts of state and encryption already solved. ruma-client is a thin client you can use when you want the protocol without the SDK's opinions.

The practical benefit of the split is that the Matrix protocol moves constantly, and the specification is a large document with many event types and many endpoints. Having that modelled once, in typed Rust, means a homeserver and a bridge written by different people agree on what a room state event is without either of them writing the parser.

The website is ruma.dev, the chat is on Matrix itself at the ruma room, and the crates are documented on docs.rs with unstable documentation at docs.ruma.dev for people tracking the git branch.

One dependency, a dozen crates, and a re-export strategy

Adding Ruma to a project is one line, and the manifest shows the two forms:

toml
# crates.io release
ruma = { version = "0.15.0", features = ["..."] }
# git dependency
ruma = { git = "https://github.com/ruma/ruma", branch = "main", features = ["..."] }

The key design decision follows immediately: ruma re-exports all of the other crates, so you do not have to worry about them as a user. You depend on one crate, turn on the features you need, and the individual crates stay an implementation detail unless you want to name them yourself.

Looking at the workspace manifest, the scale is clear. The crates directory holds the published crates, and the versions are all independent: ruma-common at 0.20.1, ruma-client-api at 0.25.1, ruma-events at 0.35.1, ruma-federation-api at 0.16.1, ruma-identity-service-api at 0.16.1, ruma-appservice-api at 0.17.1, ruma-push-gateway-api at 0.16.0, ruma-state-res at 0.18.0, ruma-html at 0.9.0, ruma-identifiers-validation at 0.13.0, ruma-signatures at 0.22.1 and ruma-macros pinned exactly at 0.20.1.

That spread is not sloppy versioning, it is a sign of how the pieces are consumed. ruma-events is the largest and moves most often because it tracks the specification's event catalogue, while ruma-html is a small utility that changes rarely. A user who depends only on the top level crate gets them all re-exported, and the ones behind it are versioned according to how often they actually need to change.

The release list confirms the pace. ruma-signatures 0.22.1, ruma-identity-service-api 0.16.1 and ruma-federation-api 0.16.1 were all published on 2026-10-19, the same day as the last push to the repository. The whole set moves together, but each crate keeps its own version number, so a dependency upgrade in a real project is a set of small version bumps rather than one large one.

Room versions, and the line Ruma draws about the old ones

The status section is the part of the README that will save you from shipping a bug, and it is worth reading twice.

Ruma 0.15.0 supports all events and REST endpoints of Matrix 1.18. That is the headline: full coverage of the specification version that the current release targets.

Then the room version rule, and it has three parts that pull in different directions. Only room versions enforcing canonical JSON, introduced with room version 6, are supported. Room versions 1 through 5 are supported on a best effort basis, but a missing feature or an incompatibility with a homeserver implementation are not considered bugs. Clients should be able to work with those room versions, granted parts of the room might break in some unconventional cases, but homeservers based on Ruma should not advertise support for them.

So the three audiences get three different answers. A client can attempt the old versions and accept breakage. A homeserver operator should not advertise them. And a bug report about an old room version will be closed, because the support is best effort by definition.

The reason is canonical JSON. A room version that does not enforce it cannot have its events verified consistently, which means signatures and state events do not behave the way the rest of the library assumes. The distinction is a spec-version boundary rather than a bug, and it is the kind of thing a library can only enforce by telling you clearly.

There is a second versioning dimension in the same section. Various changes from in-progress or finished MSCs are also implemented, gated behind unstable-mscXXXX Cargo features where XXXX is the MSC number. So the experimental surface of the Matrix ecosystem is reachable, but only if you ask for it by name.

The minimum Rust version, and the one crate that is allowed to break it

Ruma currently requires Rust 1.89, and the policy around that is stated in a way that tells you how the maintainers think about it.

In general, they will never require beta or nightly for crates.io releases of their crates, and they will try to avoid releasing crates that depend on features that were only just stabilized.

That is a compatibility commitment with two parts. The toolchain floor is on stable Rust, always, and a crate should not depend on something that was stabilized in the previous release, because that would make the crate unusable for anyone a few months behind on stable.

Then there is the exception, and it is instructive. ruma-signatures is an exception because it uses cryptographic libraries that often use relatively new features, and the maintainers do not want to use outdated versions of those libraries. The trade-off they chose is that it is guaranteed to work with whatever the latest stable version is, rather than with the stated minimum.

So if you depend on ruma-signatures specifically, you are on the latest stable Rust rather than on 1.89. If you depend on the rest of the set, 1.89 is the floor. In practice the workspace pins rust-version to 1.89 with a comment that says to keep it in sync with the README, the xtask CI source and the GitHub Actions workflow, which is a nice example of a project making the version floor hard to get out of step between the documentation and the enforcement.

The workspace itself uses resolver 3, which is the current Cargo feature resolver, and it has default-members set to crates/* with a comment explaining that only the public crates are compiled and checked by default, with the xtask tool excluded from the default build.

The repository layout, and what it tells you about how the project is run

The top level of the repository is a Cargo workspace with a clear division between the published crates, the tooling, and the web presence.

There is a crates/ directory holding the members, and an xtask/ directory, which is the standard Rust convention for a binary that automates project tasks. There is a contrib/ directory, and a wasm/ directory, which suggests some part of the set is compiled to WebAssembly, which is a plausible requirement for a protocol library that has to run in a browser context.

The workspace dependency list in the manifest is a good map of what the crates lean on. There is serde and serde_json for serialisation, thiserror for error types, tracing for instrumentation, http for the HTTP types, bytes, base64, rand, js_int and js_option for the JSON integer semantics that Matrix requires, language-tags, and criterion plus insta for benchmarking and snapshot testing. The js_int dependency is the interesting one for anyone writing their own Matrix code, because Matrix uses a specific integer width in its JSON encoding and modelling that with a dedicated type is exactly the kind of correctness the library exists to provide.

The linting and policy configuration is thorough. There is a .clippy.toml, a .deny.toml, which is the tool for auditing and denying specific dependencies, a .typos.toml for spelling, a .rustfmt.toml, and a .rumdl.toml, which is the markdown linter for the documentation. There is also a rust-toolchain.toml, which pins the toolchain the project itself builds with, separate from the minimum version it supports.

The documentation tooling has its own piece. The website is a separate repository, ruma-sites, and the docs are built with a tool called rumdl, which is the same name as the config file. There is a .github/ directory for the workflows, and a CONTRIBUTING.md at the root.

The overall shape is a project where the protocol is the product and the tooling around it is taken seriously, which is what you would expect from a library that many independent homeservers and bridges depend on.

Editorial conclusion

Adopt Ruma if you are writing a homeserver, a bridge or any software that speaks the Matrix protocol in Rust, because modelling the event and endpoint types by hand is a large and error-prone job. Do not adopt it as a ready-made client, since state storage and end-to-end encryption live in matrix-rust-sdk, and check your room versions before you rely on older ones. Before you start, read the status section, because homeservers based on Ruma should not advertise support for room versions 1 through 5, and confirm your toolchain meets the minimum Rust version of 1.89.

Frequently asked questions

What is Ruma and what is it not?

Ruma is a set of Rust crates for the Matrix chat network, providing the event, endpoint, identifier and signature types. It is not a client, because state storage and end-to-end encryption live in matrix-rust-sdk, and a low level client lives in the separate ruma-client repository.

How do I add Ruma to a Rust project?

Add ruma to your dependencies, either as a crates.io release such as ruma = { version = "0.15.0", features = ["..."] } or as a git dependency pointing at the main branch. The ruma crate re-exports all the other crates, so you do not need to depend on them individually.

Which Matrix room versions does Ruma support properly?

Only room versions enforcing canonical JSON, introduced with room version 6, are supported. Versions 1 through 5 are supported on a best effort basis, where a missing feature or an incompatibility is not considered a bug, and homeservers based on Ruma should not advertise support for them.

What Rust version does Ruma require?

Ruma currently requires Rust 1.89, and the project says it will never require beta or nightly for crates.io releases. The exception is ruma-signatures, which uses cryptographic libraries that need relatively new features, so it is guaranteed to work with the latest stable version instead.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. ruma/ruma on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ruma-ruma.svg)](https://hysenlabs.com/projects/ruma-ruma)

Was this useful?