69 million WhatsApp messages are sent globally as you read this sentence. Messages on the app don’t freeze and calls don’t stagger.
How does the chat app handle so much data without performance issues?
Erlang, the functional programming language, is one key reason.
Additionally, Erlang works even better when paired with ejabberd, an XMPP server.
In this article, I’ll show you how to use Erlang + ejabberd to build a complete messaging app like WhatsApp.
Key Takeaways
- Erlang helps apps handle millions of users, restart failed processes, and run with almost no downtime.
- Ejabberd server ensures instant message delivery, security, and smooth performance.
- Erlang + ejabberd together create a fast, secure, and crash-resistant messaging app.
- Use ejabberd for an open-source approach or MirrorFly for a ready-made, customizable solution.
- MirrorFly is easier with extensive features and customisable security. ejabberd is free but needs more setup work.
Table of Contents
What is Erlang?
Erlang is a functional programming language and runtime system designed for building concurrent, distributed, and fault-tolerant apps. It is very reliable, meaning if one part of the system fails, the rest keeps working.
Erlang is not just highly available. You can use it for:
- Handling millions of simultaneous connections with lightweight processes.
- Restart failed processes with built-in supervision trees.
- Build your chat app on a native server with distributed computing.
- Handle frequent message exchanges with messaging passing (Actor model).
- Push updates and fixes to a live chat app with minimal downtime.
💡Fact Time
Apps built with Erlang achieve extremely high availability (99.999% uptime), meaning they can run for 20 years with less than one second of total downtime
What Is Ejabberd?
ejabberd is an open-source, scalable XMPP (Extensible Messaging and Presence Protocol) server that’s written in Erlang. It supports real-time messaging, presence updates, group chats, and security features like encryption and authentication.
Since ejabberd is built in Erlang, it shares most features as the runtime environment itself. However, it extends its capabilities a bit more with XMPP-based messaging features.
What other apps can you build with XMPP? Read here
Here’s what makes ejabberd a powerful real-time chat server:
- Takes care of real-time chat, presence updates, and message delivery features in a chat app.
- Balances the load across multiple servers with a ready-to-use clustering solution.
- Uses WebSockets and HTTP binding (BOSH) to enable real-time messaging in browsers.
- You can build chat history feature with XEP-0313 (Message Archive Management).
- Stores and manages data with open-source database integrations like PostgreSQL, MySQL, MariaDB, and LDAP.
How Erlang And Ejabberd Work Together?
When a user sends a message, Ejabberd processes it quickly using Erlang’s power and delivers it in real time. If a user is offline, Ejabberd stores the message and sends it when they come back.
Erlang also helps Ejabberd run on multiple servers, so even if one part fails, the system keeps working.
Look into the flow of the chat app process:
Ejabberd can send and receive messages without downtime, even across multiple servers, because Erlang helps it work smoothly on many servers at once (distributed system).
If one server or part of the system crashes, Erlang automatically fixes it and keeps everything running (fault tolerance).
This allows Ejabberd to handle large numbers of users without interruptions (clustering & load balancing).
On the other hand, Ejabberd takes care of the security and authentication with encryption features like TLS encryption and OAuth. It combines with built-in real-time messaging features supported by Erlang to establish millions of secure, simultaneous connection (Concurrency) to initiate the message flow.
Thereby, when a user sends a message, Ejabberd quickly processes it using Erlang, then delivers it instantly to the recipient using XMPP. If the recipient is offline, Ejabberd saves the message and sends it later when they come online.
Building A Messaging App In Erlang + Ejabberd
There are 2 ways to build a messaging app in Erlang.
- ejabberd (Self-Hosted XMPP Server) – A fully open-source approach.
- MirrorFly (Self-Hosted Solution) – A custom ready-made API/SDK solution.
Building A Chat App From Scratch On ejabberd Self-Hosted Setup (Open-Source XMPP Server)
🚀 Best for: Developers who want full control over chat infrastructure. | |
✅ Pros: Fully open-source, scalable, customizable. | ❌ Cons: Requires setup and maintenance. |
🚀 Best for Developers who want full control over their chat infrastructure. | |
✅ Pros Fully open-sourceScalableCustomizable | ❌ Cons Time consumingCode-heavyRequires maintenance & setup |
Here’s a step-by-step breakdown to help you implement your Erlang chat application in a structured way:
Step 1: Install Erlang
Make sure Erlang is installed on your machine. Run the following command to check:
erl
If Erlang is installed correctly, you will see the interactive Erlang shell.
Step 2: Set Up the Project Structure
Create the following Erlang modules:
- chat_server.erl (Handles client connections)
- chat_client.erl (Represents the chat client)
- chat_fsm.erl (Handles chat state transitions)
- chat_app.erl (Supervises the application)
Step 3: Implement the Chat Client
The chat client is a gen_server responsible for sending and receiving messages.
1. Create chat_client.erl
-module(chat_client).
-behaviour(gen_server).
-export([start_link/1, send_message/2]).
-export([init/1, handle_call/3]).
-record(state, {handler_pid}).
start_link(Name) ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [{name, Name}], []).
init(Args) ->
{value, {_, Name}} = lists:keysearch(name, 1, Args),
io:fwrite("Chat client started with name: ~p~n", [Name]),
case gen_server:call({global, chat_server}, {register, Name}) of
{ok, HandlerPid} -> {ok, #state{handler_pid = HandlerPid}};
{error, Reason} ->
io:fwrite("Chat client terminated: ~p~n", [Reason]),
{stop, normal}
end.
send_message(Name, Message) ->
gen_server:call(?MODULE, {send, {Name, Message}}).
handle_call({send, {Name, Message}}, _From, State) ->
HandlerPid = State#state.handler_pid,
Reply = gen_fsm:send_event(HandlerPid, {send, {Name, Message}}),
{reply, Reply, State}.
Step 4: Implement the Chat Server
The chat server is a gen_server responsible for handling client connections.
2. Create chat_server.erl
-module(chat_server).
-behaviour(gen_server).
-export([start_link/0]).
-export([init/1, handle_call/3]).
-record(state, {clients = []}).
start_link() ->
gen_server:start_link({global, ?MODULE}, ?MODULE, [], []).
init([]) ->
io:fwrite("Chat server started...~n"),
{ok, #state{}}.
handle_call({register, Name}, {ClientPid, _Tag}, State) ->
Clients = State#state.clients,
case gen_fsm:start_link(chat_fsm, [{clients, Clients}, {name, Name}, {client_pid, ClientPid}], []) of
{ok, Pid} ->
NewState = State#state{clients = [{Name, Pid} | Clients]},
lists:foreach(fun({_, UserPid}) -> gen_fsm:send_all_state_event(UserPid, {join, {Name, Pid}}) end, Clients),
{reply, {ok, Pid}, NewState};
{error, Reason} ->
io:fwrite("Failed to start FSM: ~p~n", [Reason]),
{stop, normal, State}
end.
Step 5: Implement the Chat Handler (FSM)
Each client connection has an FSM that handles messages and client states.
3. Create chat_fsm.erl
-module(chat_fsm).
-behaviour(gen_fsm).
-export([start_link/3]).
-export([init/1, connected/2]).
-record(state, {clients, client_pid, name}).
start_link(Clients, Name, ClientPid) ->
gen_fsm:start_link(?MODULE, [{clients, Clients}, {name, Name}, {client_pid, ClientPid}], []).
init(Args) ->
Clients = proplists:get_value(clients, Args),
Name = proplists:get_value(name, Args),
ClientPid = proplists:get_value(client_pid, Args),
{ok, connected, #state{clients = Clients, name = Name, client_pid = ClientPid}}.
connected({send, {ReceiverName, Message}}, State) ->
Clients = State#state.clients,
SenderName = State#state.name,
case proplists:get_value(ReceiverName, Clients) of
undefined -> {error, no_client};
HandlerPid -> gen_fsm:send_event(HandlerPid, {receive, {SenderName, Message}})
end,
{next_state, connected, State}.
connected({receive, {SenderName, Message}}, State) ->
ClientPid = State#state.client_pid,
gen_server:call(ClientPid, {receive, {SenderName, Message}}),
{next_state, connected, State}.
connected(_Event, State) ->
{next_state, connected, State}.
Step 6: Implement the Chat Supervisor
The supervisor ensures the chat server and FSM processes remain running.
4. Create chat_app.erl
-module(chat_app).
-behaviour(application).
-export([start/2, stop/1]).
start(_Type, _Args) ->
chat_sup:start_link().
stop(_State) ->
ok.
Step 7: Start the Chat Application
- Compile the code
Run the following command inside your project directory:
erlc *.erl
2. Start the Erlang shell
erl -s chat_app
3. Start the Chat Server
chat_server:start_link()
4. Start a Chat Client
chat_client:start_link("Alice").
chat_client:start_link("Bob").
5. Send Messages
chat_client:send_message("Bob", "Hello Bob!")
Your Next Steps:
- Implement message persistence using Mnesia.
- Add a command-line interface for easier interaction.
- Enhance the FSM with multiple states (e.g., offline, online, typing).
This should give you a structured way to build and extend your Erlang chat system.
2. Building A Messaging App With MirrorFly Self-Hosted Chat Solution
Before we jump into the development steps with MirrorFly, here’s how MirrorFly + Erlang + ejabberd are related:
MirrorFly’s self-hosted solution is built on ejabberd, which runs on Erlang. Here’s how they are connected:
- MirrorFly Uses ejabberd as Its Core
- ejabberd is a powerful chat server that supports real-time messaging.
- MirrorFly improves it by adding 1000s of features like voice/video calls, push notifications, and better scalability.
- ejabberd is Built with Erlang
- Erlang makes ejabberd fast, stable, and able to handle millions of users at once.
- It ensures the chat system keeps running smoothly even if some parts fail.
- MirrorFly Simplifies Everything
- Instead of setting up and coding ejabberd yourself, MirrorFly provides:
✅ Ready-to-use chat server
✅ APIs & SDKs for easy app integration
✅ An admin dashboard to manage everything
In Simple Terms:
- MirrorFly Self-Hosted = ejabberd (chat server) + 1000s of messaging Features + Complete development in 48 hrs.
- ejabberd runs on Erlang, which makes it fast and reliable.
- You don’t need to learn Erlang. MirrorFly handles all the technical parts for you!
Ready to build with MirrorFly? In this section, we’ll talk you through the steps for developing a messaging platform with MirrorFly chat solution.
🚀 Best for 100% customization, full data control, custom security and on-premise hosting. | |
✅ Pros Fully open-sourceScalableCustomizable | ❌ Cons Time consumingCode-heavyRequires maintenance & setup |
Here’s a step-by-step guide to integrating the MirrorFly Chat SDK into your Android app:
Step 1: Set Up Your Project
- Create a new project or open an existing one in Android Studio.
- Ensure your environment meets the following requirements:
- Android 5.0+ (API Level 21 or above)
- Java 7+
- Gradle 4.1.0+
- targetSdkVersion 34 (if using SDK 7.11.4+)
Step 2: Get Your License Key
- Contact MirrorFly team and register for a MirrorFly account.
- Log in to your account.
- Find the License Key in the Application Info section.
Step 3: Add Dependencies
Modify Gradle files:
- For Gradle 6.8+ (Add this to settings.gradle):
dependencyResolutionManagement {
repositories {
mavenCentral()
google()
jcenter()
maven {
url "https://repo.mirrorfly.com/release"
}
}
}
2. Add MirrorFly SDK to app/build.gradle:
dependencies {
implementation 'com.mirrorfly.sdk:mirrorflysdk:7.13.13'
}
3. Enable Jetifier in gradle.properties:
android.enableJetifier=true
4. Add permissions in AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"/>
Step 4: Initialize SDK
Inside your Application class (MyApplication.java):
ChatManager.initializeSDK("YOUR_LICENSE_KEY", (isSuccess, throwable, data) -> {
if (isSuccess) {
Log.d("TAG", "SDK Initialized Successfully");
} else {
Log.d("TAG", "SDK Initialization Failed: " + data.get("message"));
}
});
Add MyApplication to AndroidManifest.xml:
<application
android:name=".MyApplication"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
</application>
Step 5: Register a User
FlyCore.registerUser("USER_IDENTIFIER", (isSuccess, throwable, data) -> {
if (isSuccess) {
String userJid = (String) data.get("userJid");
Log.d("TAG", "User Registered: " + userJid);
} else {
Log.e("TAG", "User Registration Failed");
}
});
💡 USER_IDENTIFIER must be alphanumeric, hyphen (-), or underscore (_) only.
Step 6: Connect to Chat Server
At this stage, you can either connect to MirrorFly’s multi-tenant chat server or your own private server or datacenter.
ChatManager.setConnectionListener(new ChatConnectionListener() {
@Override
public void onConnected() {
Log.d("TAG", "Connected to Chat Server");
}
@Override
public void onDisconnected() {
Log.d("TAG", "Disconnected from Chat Server");
}
});
Step 7: Send and Receive Messages
📩 Send a Message
TextMessage textMessage = new TextMessage();
textMessage.setToId("RECIPIENT_JID");
textMessage.setMessageText("Hello!");
FlyMessenger.sendTextMessage(textMessage, (isSuccess, error, chatMessage) -> {
if (isSuccess) {
Log.d("TAG", "Message Sent Successfully");
}
});
📥 Receive Messages
ChatEventsManager.setupMessageEventListener(new MessageEventsListener() {
@Override
public void onMessageReceived(@NotNull ChatMessage message) {
Log.d("TAG", "New Message: " + message.getMessageText());
}
});
For adding features like WebRTC video calling and SIP/ VoIP calling, refer to MirrorFly’s API documentation.
Choosing The Right Solution For Building Chat App
Both the solutions are reliable to build a chat app in Erlang, with ejabberd server. However, if you need to choose one, here is a comparison that will help.
Feature | MirrorFly Self-Hosted Solution | ejabberd Self-Hosted |
Customization | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
Data Control | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
1000+ Features | ⭐⭐⭐⭐⭐ | ⭐⭐ |
White-labeling | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
Ease of Setup | ⭐⭐⭐⭐ | ⭐ |
Scalability | ⭐⭐⭐⭐⭐ | ⭐⭐ |
Security | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
Cost | 💰💰 (One-time fee) | Free (Open-Source) |
Overall, we’ll recommend you to go for MirrorFly self-hosted solution if you need 100% customization and data control and choose building from scratch on an ejabberd server if you prefer an open-source approach.
The decision is completely up to you.
If you’d like to get some help with making the decision, contact this expert team and they’ll get in touch with you in the next 24 hrs.
Ready To Add Instant Messaging Features In The Next 48 Hrs?
MirrorFly comes with 1000s of features and 100% customization – And we can’t wait to see what you build!
Talk to us200+ Happy Clients
Unlimited Instant Messaging
Multi-user Support

Frequently Asked Questions
Ejabberd is a Erlang XMPP server software that handles real-time messaging. It’s ideal for building chat messaging app because it provides ready-made infrastructure for message routing, storage, and error handling across platforms. Instead of building these complex systems from scratch, developers can use ejabberd as a foundation and focus on building their client-side applications.
Erlang is excellent for real-time messaging app because it offers high performance with low latency, reliable message delivery, and handles concurrent user connections efficiently. Its built-in support for fault tolerance keeps the system running smoothly, while its lightweight processes make development and maintenance simpler compared to other languages.
To build an Ejabberd/Erlang chat app, you need to install Erlang, MySQL database, and Ejabberd server software along with several system dependencies. The core setup consists of an Ejabberd chat server for message handling and a WebRTC signaling server for connections. You’ll also need to configure Ejabberd for authentication and database integration, while following proper code style guidelines during development.
To build a one to one chat app using ejabberd & Erlang, follow the steps of this Ejabberd tutorial
Download and extract Ejabberd on your Ubuntu server
Install required dependencies
Install Ejabberd and verify the installation
Modify the configuration file for your needs
Start the Ejabberd server
Test the connection via localhost to ensure it’s running properly
Related Articles
- How To Build a Real Time Chat App for iOS and Android?
- 10 Best Customizable Chat Software For Enterprises Of All Sizes!
- What is Data Ownership & Why is it Important?
- What is VoIP – A complete guide for developers and businesses
What are the cons of to building 1 to 1 chat app in firebase?
Two major reasons:
i) No straightforward API available for sending push notification from one device to another (without the use of a separate backend).
ii) No inbuilt encryption, you would have to implement your own encryption for chatting.
What are the libraries using in firebase?
List of libraries that we’ll use to build the chat app:
firebase – the client-side libraries for applications that use Firebase services
react – a JavaScript library for building user interfaces
react-native – a framework for building native apps with React
redux ‒ a state management library for JavaScript applications
eslint ‒ a linting utility for JavaScript applications
relative-date – JavaScript module for outputting relative dates
The tutorial which is more helpful for the new developer to build a one to one chat app. Thanks for sharing the article!
Hey Alex,
Nice post. I am developing a one to one chat application in Android. This blog helped me and also clarified the doubts.
Looking for further updates.
Which technology is best to implement one to one messenger in the iOS app. Is it Ejabberd or Firebase?
Good tutorial. Shall I follow the above steps to build group messaging chat app?
Looking for a reply.
Good job! Looking forward to a tutorial of group chat.
Other members upon accepting the request can have private chat with them. … We’ll be making use of AngularJS 1 for this tutorial. Download the AngularJS …. There are many ways I could improve this application.