TI

Tinode

Open-source instant messaging server

Matrix & XMPP ★ 13.5k stars Medium setup GPL-3.0

Tinode is an open-source instant messaging server with a backend and clients designed as an alternative to closed messengers. It targets developers building chat into products. It is deployed via Docker or binaries.

Key features

  • Lightweight messaging server
  • Web, mobile and CLI clients
  • Group and peer-to-peer chats
  • Pluggable storage backends

Pros & cons

Strengths

  • Good developer foundation
  • Multiple clients
  • Lightweight

Trade-offs

  • More toolkit than product
  • Smaller community

Tinode replaces

Last reviewed Aug 26, 2026 · 844 words

Tinode is a chat server for developers who need messaging inside something they are building. If you want to move your family or team off WhatsApp or Slack, this is the wrong page and you want Matrix or one of the team-chat products; I will say which at the end. If you are shipping an app and need one-to-one and group chat with typing indicators, read receipts, presence, and clients you can restyle, Tinode gives you a working backend in Go, a reference web client, native Android and iOS clients, and a licence (GPL-3.0) that lets you modify all of it. The catalogue's phrase "more toolkit than product" is exactly right and it cuts both ways.

What is in the box

One Go binary serves three transports: WebSocket, HTTP long polling for hostile networks, and gRPC for server-to-server and bot integrations. Default ports are 6060 for HTTP and WebSocket and 16060 for gRPC. The message model is topics rather than rooms: a p2p topic between two users, a grp topic for groups, a me topic for a user's own presence and contact list, and a fnd topic for search. Clients ship as TinodeWeb (React, embeddable), Tindroid for Android, Tinodios for iOS, and tn-cli, a Python command-line client that doubles as a bot framework. Attachments go through a file store that can be local disk or S3-compatible. Push notifications use Firebase Cloud Messaging for mobile, which means a Google project even for a self-hosted server; there is no built-in UnifiedPush path.

Pick the storage backend before the first message

Tinode is unusual in supporting four databases through pluggable adapters: MySQL, PostgreSQL, MongoDB, and RethinkDB (the original). The Docker images are published one per backend as tinode/tinode-mysql, tinode/tinode-postgres, tinode/tinode-mongodb, and tinode/tinode-rethinkdb. Switching later means a data migration you write yourself, so choose the one you already run and back up. For a self-hoster that is PostgreSQL.

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: tinode
      POSTGRES_PASSWORD: change-me
      POSTGRES_DB: tinode
    volumes:
      - pg:/var/lib/postgresql/data

  tinode:
    image: tinode/tinode-postgres:latest
    depends_on: [db]
    environment:
      POSTGRES_DSN: "postgresql://tinode:change-me@db:5432/tinode?sslmode=disable"
      RESET_DB: "false"
      UPGRADE_DB: "true"
    ports:
      - "6060:6060"
    volumes:
      - uploads:/uploads

volumes:
  pg:
  uploads:

The first start initialises the schema and creates a demo dataset unless you pass SAMPLE_DATA=false; check the image documentation for the current variable names, because they have changed between releases. RESET_DB=true wipes everything, which is fine on day one and catastrophic on day 200. Put Caddy or Traefik in front with WebSocket passthrough (both handle it without special configuration) and the web client works over HTTPS. Memory at idle is well under the catalogue's 256 MB minimum; Go is kind here.

What it deliberately does not do

No federation: two Tinode servers do not talk to each other, and there is no bridge to Matrix, XMPP, or anything else. No end-to-end encryption: messages are encrypted in transit and stored in plain text in your database, which is acceptable for an in-app support chat and unacceptable for a private messenger. No phone-number identity or contact discovery beyond what you build. The permission model is capable (per-topic access modes down to who can see whom) but it is expressed as letter strings like JRWPA that you will be reading the documentation to decode. Community size is modest, so when something breaks you are reading Go source rather than a forum thread. None of these are flaws for the intended audience; they are the reasons it is not a consumer product.

Where it sits against the things people compare it with

Synapse or conduwuit give you Matrix: federation, end-to-end encryption, bridges to almost everything, and clients you do not have to build, at the cost of a heavier server and a protocol that is not designed for embedding in your own app. Rocket.Chat and Mattermost are finished team-chat products with admin consoles, integrations, and compliance features; they replace Slack, which Tinode does not try to. Tinode's competition is really the hosted chat SDKs (Stream, Sendbird, PubNub) that charge per monthly active user, and against those it wins on price and control the moment your user count is non-trivial. The rest of the Matrix and XMPP category covers the protocol-based options if federation matters.

What I'd do

Building a product that needs chat: Tinode on the PostgreSQL image behind Caddy, the web client forked and restyled, tn-cli for the first bot, and a plan for push notifications that accepts the Firebase dependency or replaces it with a WebSocket-only web app. Replacing WhatsApp for a household: conduwuit and Element. Replacing Slack for a team: Mattermost. Tinode is a good foundation for the first case and a mismatch for the other two, and knowing which case you are in is most of the decision.

Compare Tinode

27 head-to-head comparisons.

Similar matrix & xmpp apps