# Stoat Backend: self-hosting the Rust services behind Stoat chat

> Stoat Backend is the Rust workspace that runs the Stoat chat service: a REST API, a WebSocket event server, and media, proxy and push daemons. This is what the repository documents, what a docker compose install involves, and where it stops being the right choice.

**stoatchat/stoatchat** — The software powering Stoat

- Repository: https://github.com/stoatchat/stoatchat
- Website: https://developers.revolt.chat/api/
- Stars: 3,368 · Forks: 393
- Language: Rust
- License: NOASSERTION
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/stoatchat-stoatchat

## What Stoat Backend actually is, and who it is for

The README describes the repository as "the services and libraries that power the Stoat service". It is not a single binary and not a client. It is a Cargo workspace whose members are grouped into three kinds: crates/delta (the REST API server), crates/bonfire (the WebSocket events server), and crates/services/* for the peripheral HTTP services, with crates/core/* holding shared libraries such as config, database, files, models, permissions, presence, result and coalesced. crates/daemons/* holds background workers, and the Dockerfile names three of them: crond, pushd and voice-ingress.

The audience follows from that layout. This is for an operator or a backend engineer who wants to run a chat service themselves and is willing to assemble several stateful dependencies to do it. Someone looking for a desktop application to install has the wrong repository: the client is not here. Someone looking for a drop-in hosted product is also in the wrong place, since every service in the tree expects a database, a cache and a message broker to already exist.

## The service split: delta, bonfire and the side services

The architecture is a fan-out of small processes over shared state. Delta is the REST API server. Bonfire is the WebSocket events server, which is how a client receives live updates rather than polling delta. The README's table also lists services/january as a proxy server, services/gifbox as a Tenor proxy server, and services/autumn as a file server. Autumn is the piece that talks to object storage: the core/files crate is described as "S3 and encryption subroutines", so media handling is split between an HTTP service and a shared library.

The shared crates are where the behaviour that every process needs lives. core/permissions is "Permission Logic", core/presence is "User Presence", core/coalesced is described as a "Coalescion service", and core/ratelimits appears in the Dockerfile's dependency list even though the README table shown here does not reach that row. The practical consequence is that you cannot run delta and bonfire as isolated units. They share database and cache configuration, and the compose file provisions exactly those dependencies: KeyDB in place of Redis, MongoDB with a replica set, an S3-compatible storage server, and RabbitMQ. That is four stateful services before any Stoat process starts.

## Installing with stoatchat docker compose

The repository ships a compose.yml that provisions the dependencies. The services are named redis (image eqalpha/keydb, port 6379), database (image mongo, command mongod --replSet rs0, port 27017), minio (image docker.io/pgsty/silo, ports 14009 and 14010), a createbuckets one-shot job that makes the revolt-uploads bucket, and rabbit (image rabbitmq:4-management, port 5672). The database service carries a healthcheck that runs rs.initiate against rs0, so the replica set is initialised by the container itself rather than by a manual step.

Start the stack from the repository root:

```bash
docker compose up -d
```

What you should see is five containers, with createbuckets exiting after it creates the bucket and the other four staying up. The MongoDB healthcheck needs a moment before it reports healthy, because the start_period is 0s and the check retries up to 30 times at 5 second intervals.

For the application itself, the Dockerfile is a three-stage build on rust:1.92.0-slim-trixie. It copies each crate's Cargo.toml first, runs scripts/build-image-layer.sh deps to build dependencies, then copies crates and runs the same script with apps. The build stage installs make, pkg-config, libdav1d-dev and libssl-dev, and takes a CARGO_BUILD_JOBS argument defaulting to 10. The README does not document how to run the resulting image against the compose stack, and it does not document a configuration file format beyond the presence of Revolt.toml at the repository root.

## Where the documentation stops and guesswork begins

The README is a crate index. It lists paths, descriptions and badges, and then stops. There is no quickstart, no environment variable reference, no migration procedure, and no statement of what a minimal working deployment looks like. The presence of Revolt.toml at the root implies file-based configuration, but the README does not describe its keys. The compose.yml gives you the dependency layer and nothing about wiring the application to it.

That gap matters more here than it would in a project with a single process. You are being asked to bring up MongoDB as a replica set, KeyDB, an S3-compatible server and RabbitMQ, then point an undocumented number of Rust services at all four. The healthcheck shows the maintainers thought about replica set initialisation; they did not document what the application does when the replica set is unavailable, or whether delta and bonfire fail fast or retry. The README is silent on both.

## The licence is not one licence

The repository reports its licence as NOASSERTION, and the README table shows why that is not just a metadata failure. The core crates carry Crates.io licence badges, while delta, bonfire, services/january, services/gifbox and services/autumn are each marked AGPL-3.0-or-later in the table. So the workspace mixes a set of published library crates with AGPL-licensed servers.

If you plan to modify the servers and expose them over a network, the AGPL marking on those crates is the thing to read in full, not the repository-level licence field. The core crates are published to Crates.io under names such as revolt-config, revolt-database, revolt-files, revolt-models, revolt-permissions, revolt-presence, revolt-result and revolt-coalesced, which suggests they are intended for reuse outside this tree. The README does not state which licence each of those carries. This is a description of what the files say, not legal advice; if the distinction affects your deployment, read the LICENSE file and the individual crate manifests.

## Upgrade cost and what the release history shows

The repository is not archived and the last push was on 2026-09-23, so the tree is being changed. Recent releases are v0.15.3 on 2026-08-27, v0.15.4 on 2026-09-01 and v0.15.5 on 2026-09-12, which is a cadence of roughly one release every one to two weeks across that window. The repository also carries .release-please-manifest.json and release-please-config.json, so versioning and changelog generation are automated, and CHANGELOG.md is checked in.

What the repository does not show is a migration story. There is no documented schema migration path for MongoDB, no rollback procedure, and no compatibility statement about whether a v0.15.x client works against a v0.15.y backend. The Cargo.toml patches redis23 to a fork at github.com/revoltchat/redis-rs pinned to a specific revision, which means dependency updates are not purely semver-driven. Budget for reading the changelog before each bump rather than assuming a patch release is inert.

## Stoat chat vs Discord, Matrix and Mumble: what changes

The comparison that matters is architectural, not feature-by-feature. A hosted service like Discord gives you no server to run; Stoat Backend gives you the server and the four stateful dependencies it needs. Against Matrix, the difference is in the data model and the protocol surface: Stoat Backend exposes a REST API through delta and a WebSocket event stream through bonfire, and its own documentation points at developers.revolt.chat/api/, rather than implementing a federated room protocol with homeservers exchanging events. There is no federation in the repository layout.

Against Mumble or TeamSpeak, the split is even sharper. Those are voice-first servers with a persistent channel tree and a single process. Stoat Backend includes crates/daemons/voice-ingress in the Dockerfile, so voice is one daemon among several, sitting alongside a REST API, an events server, a file server and a push daemon. If all you need is low-latency voice rooms, the MongoDB, KeyDB, S3 and RabbitMQ layer is a large amount of machinery to carry for it.

## Who should run this, and what to check first

The repository rewards a specific kind of operator: someone who wants a chat backend written in Rust, is willing to read crate manifests instead of a deployment guide, and already runs MongoDB replica sets and RabbitMQ. The workspace layout makes it straightforward to see which crate owns which responsibility, and the compose file removes the guesswork from the dependency layer.

It punishes anyone who needs a supported upgrade path. Three releases in the last month with no documented migration procedure is a maintenance commitment, not a background process. Before deploying, confirm two things against the tree rather than the README: which crates your deployment actually needs to build, and which licence each of those crates carries. The Dockerfile's explicit Cargo.toml copy list is the most reliable inventory of buildable units in the repository, and the README table is the only place the AGPL-3.0-or-later markings appear.

## Conclusion

Adopt Stoat Backend if you are comfortable running MongoDB as a replica set, KeyDB, an S3-compatible store and RabbitMQ, and you want a chat backend you can modify in Rust. Do not adopt it if you need a documented upgrade and rollback path or a supported release channel, because the repository gives neither. Before you commit, verify that the compose.yml service list matches what your deployment actually needs, and read the per-crate licence fields in the README table rather than assuming one licence covers the workspace.

## FAQ

### Can I self host Stoat?

Yes. The repository ships a compose.yml that provisions KeyDB, MongoDB with a replica set, an S3-compatible storage server and RabbitMQ, and a Dockerfile that builds the Rust services. The README does not document how to wire the built application image to that compose stack.

### How do I install Stoat chat on Linux?

The documented path is Docker. Run docker compose up -d from the repository root to start the dependency services, then build the application from the Dockerfile, which uses rust:1.92.0-slim-trixie as its build stage.

### What is Stoat chat?

The README calls this repository the services and libraries that power the Stoat service. In practice it is a Cargo workspace containing the delta REST API server, the bonfire WebSocket events server, several HTTP services and background daemons, plus shared core crates.

### How does Stoat chat compare with Discord?

Stoat Backend is the server software, so unlike Discord you run the infrastructure yourself. The compose.yml gives you KeyDB, MongoDB, an S3-compatible store and RabbitMQ to operate before any Stoat process starts.

### How does Stoat chat compare with Matrix?

The repository describes a REST API server (delta) and a WebSocket events server (bonfire) rather than a federated room protocol, and no federation components appear in the workspace layout. Its own documentation points at developers.revolt.chat/api/.

## Sources

- [Issues](https://github.com/stoatchat/stoatchat/issues)
- [Project website](https://developers.revolt.chat/api/)
- [README](https://github.com/stoatchat/stoatchat/blob/main/README.md)
- [Releases](https://github.com/stoatchat/stoatchat/releases)
- [stoatchat/stoatchat on GitHub](https://github.com/stoatchat/stoatchat)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/stoatchat-stoatchat
