Matrix is the self-hosted Slack alternative that doesn’t lock you in
You want a chat platform that lives in your homelab, works with everyone (not just your Matrix friends), and doesn’t cost you a kidney in server hardware. That’s Matrix: a federated, encrypted-by-default messaging protocol. Think IRC meets Slack, but open source and owned by the community instead of some VC-funded startup that’ll rebrand and enshittify it in three years.
The problem? Matrix is just the protocol. You need a server to run it. And here’s where things get interesting: there are three major implementations, each written in a different language, each with its own philosophy about what a Matrix homeserver should be.
- Synapse (Python) — the reference implementation. Full-featured, battle-tested, can run everything. Also eats your RAM like it owes it money.
- Dendrite (Go) — the second-gen reimagining. Fast, modular, still missing a few features Synapse has. Getting better every release.
- Conduit (Rust) — the lightweight newcomer. Single binary, minimal dependencies, runs on a potato. Opinionated about what you don’t need.
So which one should you run? That depends on your use case. Let’s break it down.
The Matrix protocol in 90 seconds
You don’t need to be a protocol wizard, but knowing the basics helps you understand why these servers differ.
Matrix is event-based. Every message, reaction, room state change — that’s an event. Events get signed, stored, and replicated across servers via federation. Your @you:homeserver.com address can talk to @friend:otherserver.com just like they’re in the same room. Servers trust each other through cryptographic signatures, not permissions lists.
Rooms are the atomic unit — like Slack channels but way more flexible. They support encryption (E2EE), state events, and reactions. User accounts live on one homeserver (yours). Everything else — rooms, direct messages, communities — is federated.
That federation is the whole point. You control your data. You’re not renting a seat on someone’s SaaS platform.
Synapse: The mature, feature-complete road hog
Synapse is the reference implementation. It’s what the Matrix core team originally built. Everyone else is chasing parity with Synapse because Synapse supports basically everything the protocol can do.
The good:
- Every feature works. New room versions? Supported. Bridges to Discord, Slack, IRC? Multiple implementations exist (mautrix-*, Bifrost). Widgets? Go for it. Server-side search? Yes. Admin APIs for user management? Obviously.
- Absolutely battle-tested. It’s been running production servers since 2015. The bugs you’d find have likely already been found and fixed.
- Tons of plugins and extensions. The ecosystem built around Synapse is massive.
- Room versions. Synapse supports all of them, including the latest cryptographic improvements.
The bad:
- It’s written in Python. Python isn’t fast. Synapse uses Twisted (async IO), which helps, but you’re still running a dynamic language that does a lot of work.
- Memory footprint. A fresh Synapse install takes ~300-500 MB. Add a few active rooms, users, and federation traffic, and you’re looking at 2-4 GB easily. I’ve seen Synapse instances hit 6+ GB after a year of daily use.
- Startup time. On smaller hardware, Synapse can take 30-60 seconds to start. Dendrite? 2-3 seconds.
- Disk usage. Synapse caches events aggressively. A year of homelab chatting can balloon to 5-10 GB of SQLite or PostgreSQL database.
- CPU spikes during sync. When clients reconnect, Synapse has to reconstruct the entire room state. It’s not pretty.
Who should run Synapse?
- Small communities (10-100 people) where you need all the bells and whistles.
- Anyone running a relay/bridge to external services that requires Synapse.
- Teams that already know Python and want to hack on the source.
- You’re running on a beefy server and RAM isn’t a constraint.
Dendrite: The polished-up younger sibling
Dendrite is the rewrite. The Matrix team learned from Synapse and built Dendrite in Go, treating it as a chance to rethink the architecture. It’s componentized — the client API, federation, media storage, and room state can run as separate services. You can scale horizontally.
The good:
- Fast. Go + static compilation. A Dendrite instance starts in seconds.
- Lower memory footprint. Dendrite typically uses 150-400 MB, even with active rooms.
- Polylith mode. Run multiple Dendrite services across machines. Chat component on one box, federation on another. This is where Dendrite shines for scaling.
- Modern design. Dendrite was built with federation and reliability in mind from day one.
- Room versions. Full support for modern room versions and encryption.
The bad:
- Still catching up to Synapse. Some features are missing: admin APIs are less complete, some bridge implementations don’t play nice with Dendrite, widget support is iffy.
- Monolith mode isn’t production-ready. The single-binary deployment is simpler, but the componentized (polylith) mode is where Dendrite wants to be. That means more complexity.
- Smaller ecosystem. Fewer third-party tools and integrations have been battle-tested with Dendrite.
- Documentation lags. Synapse’s docs are miles ahead. Dendrite’s are improving but still rough in places.
Who should run Dendrite?
- Small homelabs where you want low resource usage but full feature parity eventually.
- Anyone planning to scale beyond one box. Dendrite’s componentized design means you can shard federation or media handling.
- Teams willing to hit issues that haven’t been filed yet and report them.
- You’re comfortable saying “no” to some Synapse features you don’t actually need.
Conduit: The lean, opinionated alternative
Conduit is written in Rust. It’s a single binary. It doesn’t try to be Synapse. Instead, it asks: “What’s the minimum viable homeserver?” and builds exactly that.
The good:
- Tiny. The binary is ~30 MB. Running instances hover around 20-100 MB RAM depending on activity.
- Single binary. Copy one file to your server, add a systemd unit, done. No Python venvs, no Go services to orchestrate.
- Fast startup. Literally seconds. Great for containers.
- Works out of the box. Conduit ships with sane defaults. You don’t have 47 config options to mess with.
- Matrix protocol compliance. Conduit implements the core protocol correctly. Federation works.
- Modern codebase. Rust forces you to think about concurrency and memory safety upfront.
The bad:
- Feature surface is intentionally small. No widget support. Some bridges don’t work. The admin API is minimal. If you need 47 Synapse features, Conduit supports maybe 12 of them — on purpose.
- Smaller community. Dendrite has more eyes than Conduit. Conduit has fewer people reporting bugs and fewer quick fixes.
- Database schema is still evolving. Upgrades between Conduit versions can require migration steps. Not scary, but more friction than Synapse.
- E2EE compliance. Conduit supports encryption, but the story around backup and recovery is less polished than Synapse.
Who should run Conduit?
- Solo users or small families (3-8 people) who want simple, reliable chat.
- You’re running on tiny hardware (Raspberry Pi, ARM box, shared hosting).
- You want the absolute simplest deployment story.
- You don’t need bridges to 47 other platforms. If you need bridges, Conduit might feel too limited.
Head-to-head comparison
| Feature | Synapse | Dendrite | Conduit |
|---|---|---|---|
| Language | Python | Go | Rust |
| Memory (idle) | 300-500 MB | 150-250 MB | 20-50 MB |
| Memory (active) | 2-6+ GB | 400-800 MB | 50-150 MB |
| Startup time | 30-60s | 2-5s | 1-2s |
| Room versions | All | All | All modern |
| E2EE | Yes | Yes | Yes |
| Bridges | Extensive (mautrix-*, Bifrost) | Most work | Limited (some incompatibilities) |
| Admin API | Full-featured | Partial | Minimal |
| Widgets | Yes | Partial | No |
| Polylith/scaling | Not designed | Yes (multiple components) | No (single binary) |
| Configuration | Complex (many options) | Moderate | Simple (opinionated defaults) |
| Community size | Largest | Growing | Smallest |
| Single-user focus | Not really | Not really | Yes |
Installation and deployment
Let’s get concrete. Here’s how you’d run each in Docker.
Synapse with Docker Compose
version: '3.8'
services: postgres: image: postgres:16-alpine environment: POSTGRES_DB: synapse POSTGRES_USER: synapse POSTGRES_PASSWORD: your_secure_password volumes: - postgres_data:/var/lib/postgresql/data restart: unless-stopped
synapse: image: matrixdotorg/synapse:latest environment: SYNAPSE_SERVER_NAME: example.com SYNAPSE_REPORT_STATS: 'no' LD_PRELOAD: /usr/lib/x86_64-linux-gnu/libjemalloc.so.2 volumes: - synapse_data:/data ports: - "127.0.0.1:8008:8008" depends_on: - postgres restart: unless-stopped
volumes: postgres_data: synapse_data:Synapse requires PostgreSQL. Running it is straightforward, but initialization is a multi-step dance — you need to generate a config, create admin users with registration tokens, and tune settings.
Dendrite with Docker Compose
version: '3.8'
services: postgres: image: postgres:16-alpine environment: POSTGRES_DB: dendrite POSTGRES_USER: dendrite POSTGRES_PASSWORD: your_secure_password volumes: - postgres_data:/var/lib/postgresql/data restart: unless-stopped
dendrite: image: matrixdotorg/dendrite:latest environment: TZ: UTC volumes: - dendrite_data:/var/lib/dendrite - /path/to/dendrite.yaml:/etc/dendrite/dendrite.yaml:ro ports: - "127.0.0.1:8008:8008" depends_on: - postgres restart: unless-stopped
volumes: postgres_data: dendrite_data:Dendrite also uses PostgreSQL. The config is simpler than Synapse because there are fewer knobs to turn. Still, you’ll need to generate a config and register users through the admin API.
Conduit with Docker Compose
version: '3.8'
services: conduit: image: matrixconduit/matrix-conduit:latest environment: ROCKET_ADDRESS: 0.0.0.0 ROCKET_PORT: 6167 CONDUIT_SERVER_NAME: example.com CONDUIT_ALLOW_REGISTRATION: 'true' volumes: - conduit_data:/var/lib/matrix-conduit ports: - "127.0.0.1:6167:6167" restart: unless-stopped
volumes: conduit_data:Conduit is beautifully simple. No external database. It uses RocksDB internally. Environment variables for config. Done.
Reverse proxy: Caddy for all three
All three need a reverse proxy for TLS and .well-known federation endpoints. Here’s a Caddy config that works with any of them:
matrix.example.com { reverse_proxy localhost:8008}
example.com { redir /.well-known/matrix/server matrix.example.com:443 redir /.well-known/matrix/client { status 200 body {"m.homeserver":{"base_url":"https://matrix.example.com"}} }}(If using Conduit, change port 8008 to 6167.)
Managing users and registration
Once your server is running, you’ll want to create users.
Synapse: Registration tokens
# Generate a one-time registration token (valid for 24 hours by default)docker exec synapse_container register_new_matrix_user \ -u username \ -p password \ -a \ http://localhost:8008
# Or with a token for share-based registrationcurl -X POST http://localhost:8008/_synapse/admin/v1/registration_tokens/new \ -H "Authorization: Bearer your_admin_token"Dendrite: Admin API
# Dendrite user creation via admin endpointcurl -X POST http://localhost:8008/_dendrite/admin/v2/users \ -H "Content-Type: application/json" \ -d '{ "user_id": "@username:example.com", "password": "password", "admin": false }'Conduit: Admin panel or direct API
Conduit ships with a minimal web admin panel and supports user creation via the standard Matrix APIs.
# Create user via Matrix register endpoint (if registration is open)curl -X POST http://localhost:6167/_matrix/client/r0/register \ -H "Content-Type: application/json" \ -d '{ "user_id": "username", "password": "password", "initial_device_display_name": "Desktop" }'The federation reality check
All three servers federate. But federation is hard. Here’s what to expect:
- Initial federation. When you first join a room on another server, messages might take 2-5 seconds to sync over the network. That’s normal.
- Room backfill. Synapse will try to pull 100 messages of history when you join a large room. Dendrite backfills less aggressively. Conduit backfills what it needs.
- State events. If a room has been around for years, there’s a lot of accumulated state (bans, profile changes, etc.). Synapse caches aggressively. Dendrite is smarter about it. Conduit keeps what it needs.
- Reliability. Synapse is the most robust. Dendrite is improving. Conduit works but may drop connections under heavy load (it’s not tuned for thousands of concurrent users).
For a homelab? All three federate just fine. You won’t notice the difference unless you’re in mega-sized rooms or have thousands of users.
Bridges: Talking to Discord, Slack, IRC
Want your Matrix room to mirror Discord? Or IRC? That’s what bridges do.
Synapse: Full ecosystem. mautrix-discord, mautrix-slack, mautrix-telegram, Bifrost (for everything), heisenbridge (for IRC). All tested and documented.
Dendrite: Most bridges work, but you’ll hit edge cases. The admin APIs differ just enough that some bridge setup scripts break. Doable, but rough.
Conduit: Bridges are spotty. Some work great (mautrix-discord is fine). Others assume Synapse-specific APIs. Before deciding on Conduit, check if your target bridge is compatible.
Encryption: E2EE and key backups
All three support encryption out of the box. Clients encrypt messages client-side; servers can’t read them.
- Synapse: Full key backup story. Keys saved server-side, encrypted with your password.
- Dendrite: Works, but key backup is newer. If your client’s key backup broke, recovering is harder.
- Conduit: Works. The story is simpler because Conduit is opinionated.
For personal/family use, don’t overthink this. All three are fine.
Recommendations by use case
Solo user on a Raspberry Pi or VPS: → Conduit. 20 MB RAM, single binary, no fuss. You don’t need every Synapse feature. Just chat.
Family of 4-8 people: → Conduit or Dendrite. Conduit if you want dead-simple deployment and low power. Dendrite if you want more feature parity with Synapse without the RAM overhead.
Small community (10-50 people): → Dendrite or Synapse. Dendrite if you’re budget-conscious and can tolerate some rough edges. Synapse if you need every feature and have hardware to spare.
Medium community (50-500 people) with bridges to other platforms: → Synapse. The bridge ecosystem is too good to pass up. If your community spans Matrix, Discord, IRC, and Slack simultaneously, Synapse is your only bulletproof choice.
Anything larger or mission-critical: → Synapse on a beefy server, probably in polylith mode (multiple services) or even multiple Synapse instances behind a load balancer. By that point, you’re not running a homelab anymore — you’re running infrastructure.
Final thoughts
Matrix is the chat protocol that respects your data. But the server you run matters.
Synapse is the safe choice if you have the hardware and want every feature. Dendrite is the future — it’s getting faster and more complete every release. Conduit is the minimalist’s win if you’re willing to accept intentional limitations.
No wrong choice here. Pick the one that matches your hardware and your patience for rough edges. And honestly? All three are simpler to run than you’d think. Pick one, spin it up in Docker, and get chatting.
Your friends will thank you. Your ISP’s upload bandwidth less so.