DEV Community

Cover image for How to Build a Real-Time Chat App with React Native and Node.js
Umidjon Gafforov
Umidjon Gafforov

Posted on

How to Build a Real-Time Chat App with React Native and Node.js

How to Build a Real-Time Chat App with React Native and Node.js 💬

Real-time communication is an important part of modern mobile applications.

Messaging apps, customer support systems, collaboration tools, delivery applications, and social platforms all need the ability to exchange information quickly.

A traditional REST API is excellent for many use cases, but real-time applications often need a persistent connection between the client and the server.

One practical architecture is:

```text id="j5m9xk"
React Native

WebSocket

Node.js

Database




In this article, we'll look at the main concepts behind building a real-time chat application.

## REST API vs WebSocket

With a traditional REST API, the client sends a request and waits for a response.



```text id="s6z7qn"
Mobile App
    ↓
HTTP Request
    ↓
Server
    ↓
HTTP Response
    ↓
Mobile App
Enter fullscreen mode Exit fullscreen mode

This works well for things like:

  • Fetching products
  • Creating orders
  • Updating profiles
  • Authentication

But chat applications need something different.

Imagine two users are having a conversation.

User A sends a message:

```text id="7uh0ml"
User A

Server




User B should receive the message immediately.

With WebSockets, the server can maintain an active connection:



```text id="1k6n5f"
User A ←──── WebSocket ────→ Server
                              ↕
                         WebSocket
                              ↕
User B ←──────────────────────┘
Enter fullscreen mode Exit fullscreen mode

The server can send data to connected clients without waiting for a new HTTP request.


What Is WebSocket?

WebSocket is a communication protocol that provides a persistent, two-way connection between a client and a server.

Unlike traditional HTTP requests, the connection can remain open.

```text id="4g5q1k"
Client

WebSocket Connection

Server




Both sides can send messages.

This makes WebSockets useful for:

* Chat
* Notifications
* Live dashboards
* Multiplayer games
* Collaboration tools
* Real-time tracking

---

# React Native Client

The mobile application can establish a WebSocket connection.

A simplified example:



```javascript id="p3z5q7"
const socket = new WebSocket(
  "wss://api.example.com/socket"
);

socket.onopen = () => {
  console.log("Connected");
};

socket.onmessage = (event) => {
  const message = JSON.parse(event.data);

  console.log(message);
};

socket.onerror = (error) => {
  console.error(error);
};
Enter fullscreen mode Exit fullscreen mode

Once the connection is established, the application can listen for incoming messages.


Sending a Message

When a user sends a message, the mobile application can send data through the WebSocket.

For example:

```javascript id="r8x3sl"
socket.send(
JSON.stringify({
type: "message",
conversationId: "123",
text: "Hello!"
})
);




The server receives the message and processes it.

A simplified flow:



```text id="m3j4fr"
React Native
     ↓
WebSocket
     ↓
Node.js
     ↓
Validate Message
     ↓
Save to Database
     ↓
Send to Recipient
Enter fullscreen mode Exit fullscreen mode

Node.js Backend

Node.js is well suited for applications that maintain many concurrent connections.

A WebSocket server can listen for connections:

```javascript id="n7k2ds"
socketServer.on("connection", (socket) => {
console.log("Client connected");

socket.on("message", (data) => {
const message = JSON.parse(data);

console.log(message);
Enter fullscreen mode Exit fullscreen mode

});
});




In a production application, the server would also handle authentication, validation, persistence, and message delivery.

---

# Authentication

A real chat application needs authentication.

We don't want anonymous users to connect and access private conversations.

A typical flow could be:



```text id="u9r3kl"
Login
  ↓
Node.js API
  ↓
Authentication
  ↓
Access Token
  ↓
WebSocket Connection
Enter fullscreen mode Exit fullscreen mode

The server can verify the user's identity when establishing the connection.

Then the server knows which user is connected.

For example:

```text id="x2a6pl"
User ID: 123
Connection: WebSocket #ABC




When a message arrives for user `123`, the server knows which connection should receive it.

---

# Conversations

A chat application usually contains multiple conversations.

For example:



```text id="v6f8qw"
User
 ├── Conversation A
 ├── Conversation B
 └── Conversation C
Enter fullscreen mode Exit fullscreen mode

Each conversation can have multiple messages.

A simplified database structure could look like:

```text id="z5k1nm"
Users

Conversations

Messages




A message might contain:



```json id="f8j3mz"
{
  "id": "msg_123",
  "conversationId": "conversation_1",
  "senderId": "user_123",
  "text": "Hello!",
  "createdAt": "2026-08-14T10:00:00Z"
}
Enter fullscreen mode Exit fullscreen mode

Storing Messages

WebSocket provides real-time communication, but messages should usually be stored in a database.

For example:

```text id="r5j7nx"
User sends message

WebSocket

Node.js

Database

Recipient




Why save the message?

Because users may:

* Close the application
* Lose their internet connection
* Change devices
* Open the conversation later

The database provides persistent storage.

---

# Online Status

Real-time connections can also be used to track online users.

For example:



```text id="v8q3ma"
User connects
     ↓
Online

User disconnects
     ↓
Offline
Enter fullscreen mode Exit fullscreen mode

The backend can maintain a mapping:

```text id="t3f7ny"
User 101 → Connection A
User 205 → Connection B
User 309 → Connection C




When a connection closes, the server can update the user's status.

---

# Typing Indicators

A small feature like:

> User is typing...

can also use WebSockets.

The flow could be:



```text id="n4g8pv"
User A starts typing
        ↓
WebSocket
        ↓
Server
        ↓
User B
        ↓
"User A is typing..."
Enter fullscreen mode Exit fullscreen mode

The actual text doesn't need to be sent until the user presses the send button.


Message Delivery

Real-time doesn't necessarily mean the message is permanently delivered.

Networks can fail.

A more reliable system can track message states:

```text id="s2m7qx"
Sending

Sent

Delivered

Read




This allows the application to provide familiar messaging features.

---

# Handling Reconnection

Mobile networks are unreliable.

A user might:

* Enter a tunnel
* Switch from Wi-Fi to mobile data
* Lose signal
* Lock their phone
* Put the application in the background

The WebSocket connection can therefore disappear.

The application should detect disconnections and attempt to reconnect.



```text id="a7x2pz"
Connected
   ↓
Disconnected
   ↓
Reconnect
   ↓
Connected
Enter fullscreen mode Exit fullscreen mode

A production application should also avoid reconnecting too aggressively.


Push Notifications

What happens when the recipient isn't connected?

The backend can use push notifications.

For example:

```text id="k3n8wp"
Sender

Node.js

Recipient Offline?

Push Notification

iOS / Android




When the user opens the application, the app can then synchronize the latest messages from the backend.

This gives us two complementary systems:



```text id="m8f2vx"
WebSocket
→ Real-time communication

Push Notifications
→ Notify users when offline
Enter fullscreen mode Exit fullscreen mode

Scaling the WebSocket Server

One WebSocket server may be enough for a small application.

But imagine thousands or millions of concurrent connections.

You may eventually need multiple server instances:

```text id="b4y7nm"
Load Balancer
/ | \
↓ ↓ ↓
Server Server Server
\ | /
└── Redis ──┘




A shared system such as Redis can help coordinate information between server instances.

For example:



```text id="d6k2rx"
Server A
   ↓
Redis
   ↓
Server B
   ↓
User
Enter fullscreen mode Exit fullscreen mode

This becomes important when a sender and recipient are connected to different backend instances.


Security

Real-time systems also need strong security.

Important areas include:

  • Authentication
  • Authorization
  • Input validation
  • Rate limiting
  • Secure WebSocket connections
  • Message validation
  • Access control

Use:

```text id="w4c9hs"
wss://




instead of an unencrypted WebSocket connection when running in production.

---

# Complete Architecture

Putting the pieces together:



```text id="q8m2kd"
                    React Native
                    Mobile App
                         │
                         │
                 REST API / WebSocket
                         │
                         ↓
                   Node.js Backend
                         │
              ┌──────────┼──────────┐
              ↓          ↓          ↓
           Redis      Database    Push Service
              │
              ↓
       WebSocket Servers
              │
              ↓
       Other Connected Users
Enter fullscreen mode Exit fullscreen mode

REST APIs can handle normal application operations, while WebSockets handle real-time communication.

This combination is often more practical than trying to use only one communication method.


When Should You Use WebSockets?

WebSockets are useful when information needs to update quickly.

Good examples include:

  • Chat applications
  • Live notifications
  • Real-time dashboards
  • Delivery tracking
  • Multiplayer applications
  • Collaborative editors
  • Trading interfaces

For simple CRUD applications, however, a normal REST API may be completely sufficient.

Not every application needs WebSockets.


Final Thoughts

Building a real-time chat application requires more than opening a WebSocket connection.

A production-ready system needs:

  • Authentication
  • Message persistence
  • Reliable delivery
  • Reconnection
  • Push notifications
  • Security
  • Database design
  • Monitoring
  • Scalability

A practical architecture can combine:

React Native + WebSocket + Node.js + Database + Push Notifications

The important part is not simply making messages appear instantly.

It's building a system that remains reliable when users disconnect, reconnect, switch devices, and communicate at scale.

Real-time UX starts with reliable architecture. 🚀

Top comments (0)