How to Create a Messaging App: Architecture and Cost
A messaging app looks like three simple screens and operates like a distributed database underneath. Here is how to engineer WebSocket and MQTT connections, ULID idempotency, Signal Double Ratchet vs RFC 9420 MLS encryption, SQLite FTS5 sync, and 2026 costs.

On this page

Learning how to create a messaging app begins with seeing past a deceptive user interface: a conversation list, a scrolling thread of bubbles, and a text input bar look like a weekend prototype, yet underneath they hide a distributed state-synchronization engine. Every message a user taps send on must cross flaky cellular handoffs, survive tunnel dropouts, land in the recipient's inbox exactly once, preserve strict causal ordering across multiple devices, and wake a suspended phone without draining its battery.
At Idealogic, where our engineers build high-concurrency real-time products across our social and creator economy practice and shipped the Ugreator platform, we treat chat app development as a storage, cryptography, and protocol problem first. This guide walks through the exact production architecture required in 2026: persistent connection gateways, ULID idempotency and monotonic ordering, Signal Protocol vs IETF RFC 9420 (MLS) end-to-end encryption, on-device SQLite FTS5 indexing, battery-aware push wakeups, and realistic development budgets.
The short version
- Delivery guarantees rely on client ULIDs and server sequence numbers: Clients generate a UUIDv7 (RFC 9562) or ULID idempotency key before sending so retries never create duplicate bubbles, while the server assigns a per-conversation monotonic sequence integer to establish canonical order.
- Persistent sockets handle foreground speed; APNs and FCM handle the background: Active apps communicate over IETF RFC 6455 WebSockets or MQTT with exponential backoff and full jitter, while backgrounded apps rely on APNs Notification Service Extensions and FCM high-priority data pushes.
- Match encryption to group size and product requirements: Use TLS plus encryption at rest for B2B apps requiring server-side search and compliance, Signal Protocol (X3DH + Double Ratchet) for 1:1 and small private groups, and IETF RFC 9420 (MLS) for encrypted groups scaling past 1,000 members.
- Flip from fan-out-on-write to fan-out-on-read for large channels: Direct messages and small groups push message pointers into each member's inbox at write time, whereas 100,000-member broadcast channels store the message once and read by cursor.
- Keep media out of the socket and search on the device: Photos, voice notes, and videos upload out-of-band via AES-256-GCM encrypted chunks to S3/R2 object storage, while local SQLite WAL databases with FTS5 power instant offline search.
- Budget $55k to $110k for a focused MVP, or $120k to $220k with E2EE: Cross-platform React Native or Flutter clients paired with a Go, Rust, or Elixir gateway ship in 10 to 16 weeks for standard chat and 16 to 26 weeks with multi-device E2EE.
Persistent connection transport: WebSockets, MQTT, and reconnection physics
Standard HTTP request-response polling wastes radio power and introduces multi-second delays because the server cannot push frames to a client unprompted. A real-time messaging app holds a stateful, full-duplex transport connection open whenever the app is in the foreground.
Separating durable state from ephemeral signals
Routing every real-time event through the same database pipeline is a classic early mistake. Traffic on a messaging socket divides into two categories with opposite storage rules:
- Durable state (Messages, edits, reactions, read watermarks): Must be persisted to disk (PostgreSQL, ScyllaDB, or Cassandra) before the server returns an acknowledgment frame.
- Ephemeral state (
typing_started,online_presence, live waveform indicators): Describes only the current three-second window. Ephemeral events must never touch disk; they route strictly through in-memory gateway state or Redis Pub/Sub with a 5-second TTL.
Reconnection storms: exponential backoff with full jitter
Mobile sockets die constantly in elevators and Wi-Fi-to-5G handoffs. Worse, after a gateway deploy or load-balancer blip, 100,000 phones attempt to reconnect simultaneously. Clients must implement capped exponential backoff with full jitter:
With T_base = 500 ms and T_max = 30 s, reconnect attempts spread evenly across a widening window instead of spiking in lockstep.
Message ordering, idempotency, and the delivery state machine
Users judge a messaging app by one contract: when I tap send on a subway train with one bar of signal, my message must never vanish, must never appear twice, and must land in the exact right chronological slot.
1. Achieving effectively-once delivery via client ULIDs or UUIDv7
Suppose a user sends "See you at 8pm", the server writes the message, and the train enters a tunnel before the ACK packet arrives. The client must retry when signal returns.
If the server assigns message IDs on arrival, that retry creates a duplicate bubble. Instead, the client generates a time-ordered 128-bit identifier before the first network attempt using a ULID or IETF RFC 9562 UUIDv7 (embedding a 48-bit Unix millisecond timestamp plus random bits so B-tree indexes never fragment). The server enforces a unique constraint on (conversation_id, client_message_id). When the retry arrives, the database skips the duplicate write (ON CONFLICT DO NOTHING) and re-sends the original SERVER_ACK.
2. Why client timestamps fail for ordering, and how conv_seq fixes it
Never sort a chat thread by the sender's device clock (sent_at). Phone clocks drift by seconds or minutes, so if Alice's clock is 45 seconds behind Bob's, her replies render above the questions Bob just asked.
Canonical ordering requires a per-conversation monotonic sequence integer (conv_seq) assigned atomically by the server (1, 2, 3, ...). While a message waits in the sender's offline outbox, the UI renders it at the bottom in a pending state (conv_seq = null). Once the server ack returns { client_msg_id, conv_seq: 482, server_ts }, the client slots the message into position 482.
3. The four-stage receipt state machine and watermark compression
Every message transitions through four explicit states:
PENDING(Clock icon): Written to the sender's local SQLiteoutboxtable in WAL mode; awaiting socket availability.SENT(Single checkmark): Committed to the server's durable log;conv_seqassigned and returned.DELIVERED(Double gray checkmark): Pushed to at least one recipient device over the socket or background push extension, which emitted aDELIVERY_ACK.READ(Double blue/amber checkmark): The recipient scrolled pastconv_seq: 482, emitting a single conversation read watermark ({ user_id, conversation_id, last_read_seq: 482 }) that marks all messages up to482read in O(1) space.
The difference between a demo chat app and a production messenger shows up inside an elevator. If your client generates a UUIDv7 before touching the network, writes to a local SQLite outbox first, and reconciles order via server sequence cursors on reconnect, the user never notices the network dropped at all.
End-to-end encryption (E2EE): Signal Double Ratchet vs IETF MLS (RFC 9420)
Standard transport encryption (TLS 1.3 in flight plus AES-256 at rest) protects data from network attackers while preserving server-side search, AI summarization, and compliance archiving. End-to-end encryption (E2EE) guarantees that only client devices hold decryption keys; your servers relay opaque ciphertext. E2EE is essential for private consumer messengers, healthcare, or executive comms, but removes server-side search and requires multi-device key provisioning plus encrypted key backups (PIN-derived HSM vaults or passkeys).
1:1 and small-group E2EE: The Signal Protocol (X3DH + Double Ratchet)
For 1:1 chats and groups under 100 participants, the industry standard is the Signal Protocol (X3DH and Double Ratchet specifications):
- Asynchronous Session Setup via X3DH: On registration, Bob uploads a Pre-Key Bundle to the key server: his Identity Key (IK_B), Signed Pre-Key (SPK_B), and single-use One-Time Pre-Keys (OPK_B). Alice fetches a bundle and derives a shared root key (SK) immediately even while Bob's phone is off.
- Per-Message Forward Secrecy and Post-Compromise Security via Double Ratchet: Every message advances a symmetric KDF Ratchet (deriving a single-use message key deleted immediately after decryption for forward secrecy), while every round-trip reply carries a new Diffie-Hellman key that advances the DH Ratchet (providing post-compromise healing).
- Small Groups via Sender Keys: Each sender distributes a symmetric chain key to the group via pairwise E2EE sessions. However, whenever a member leaves or is removed, every remaining member must rotate and redistribute their Sender Key (O(N) complexity).
Large-group E2EE (1,000+ members): IETF RFC 9420 Messaging Layer Security (MLS)
When an encrypted group scales to 1,000 or 50,000 members with frequent membership churn, O(N) pairwise Sender Key rotation stalls clients. The IETF standardized RFC 9420 (Messaging Layer Security / MLS), built atop IETF RFC 9180 (Hybrid Public Key Encryption / HPKE):
- MLS places every member device at the leaf of a binary cryptographic tree (TreeKEM), where interior nodes hold keys shared by their subtree.
- When a member joins, leaves, or rotates keys in a 4,096-member group, the commit message only encrypts new path secrets for the log2(4096) = 12 sibling nodes along the path to the root instead of 4,095 pairwise operations.
Multi-device sync, fan-out architecture, and local SQLite FTS5 search
Users expect to start a message on an iPhone, switch to a laptop or browser, and see read states, drafts, and search results stay in lockstep.
Inbox fan-out: write-time vs read-time hybridization
- 1:1 and bounded groups (Fan-out on write): Each user or E2EE device maintains a per-device Sync Log (
device_inbox_events) indexed byuser_sync_seq. Sending to a 15-person group appends the event to all 15 sync logs. Reconnecting after an airplane flight requires one delta query (GET /sync?after_seq=19402) to replay every missed message, edit, reaction, and deletion in order. - Large broadcast channels (Fan-out on read): Posting to a 200,000-member channel cannot write 200,000 inbox rows. Above 500 members, store the message once in the channel partition (
(channel_id, conv_seq)), push a lightweight pub/sub notice to online subscribers, and let offline members fetch the channel tail on demand.
Local storage and on-device full-text search with SQLite FTS5
Production mobile clients treat on-device SQLite as the primary UI data source:
- Enable WAL (Write-Ahead Logging) mode (
PRAGMA journal_mode = WAL;) so background sync writes never block 120 fps scrolling. - Index decrypted text in a virtual SQLite FTS5 table:
- Encrypt the SQLite file with SQLCipher (AES-256), storing the master key in the iOS Keychain (
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly) or Android Keystore per OWASP MASVS v2.1 (MASVS-STORAGE).AfterFirstUnlockThisDeviceOnlylets background push extensions decrypt incoming messages while the screen is locked.
Out-of-band encrypted media attachments
Never push 10 MB photos or voice notes through WebSocket or MQTT brokers. Instead, the client encrypts the file locally with an ephemeral 256-bit AES-GCM key (K_file), uploads the ciphertext directly to S3 or Cloudflare R2 via a pre-signed URL, and sends a 300-byte chat message containing { blob_url, file_key, iv, sha256_hash, blurhash_preview, dimensions } inside the Signal/MLS ciphertext. If your app expands into live video rooms, that pipeline connects into the architecture we cover in how to build a live streaming app.
Push wakeups, battery budgets, and UGC compliance
Because iOS and Android suspend background sockets, reaching offline users relies on platform push services:
- iOS APNs: Send
"mutable-content": 1and"apns-priority": "10"to wake the Notification Service Extension (30-second window, ~24 MB RAM limit), which advances the ratchet in the shared App Group SQLCipher database, updates FTS5, and displays the decrypted banner. - Android FCM: Send a high-priority data push (
"priority": "high") to wakeFirebaseMessagingService, decrypt locally, and post to theMessagingStylenotification channel.
App store UGC rules, battery-aware presence, and E2EE moderation (Message Franking)
Even in end-to-end encrypted apps, Apple's App Store Review Guidelines (Section 1.2), Google Play's User-Generated Content Policy, and the EU Digital Services Act (Regulation (EU) 2022/2065) mandate working abuse reporting, immediate user blocking, and anti-spam controls before an app passes review.
To verify an abuse report in an E2EE messenger where the server never sees plaintext, production platforms implement cryptographic message franking: when a user taps Report Message, the recipient's client selectively reveals the decrypted message plaintext along with the sender's cryptographic signature and the server's HMAC delivery stamp to the moderation queue. That proves mathematically that the reported sender transmitted that exact abusive payload without weakening encryption for any un-reported conversation. Pair message franking with on-device safety classifiers (such as CoreML or TensorFlow Lite nudity blurring on unsolicited DM attachments, standard in modern dating app development) and server-side graph rate limits that throttle accounts attempting to open 30 new 1:1 threads per minute.
Presence indicators (online now, last seen 4m ago) must obey the same mobile battery budget. Never hold a background socket open just to paint a green dot. Instead, clients emit a lightweight 30-second heartbeat only while foregrounded, and the gateway only broadcasts presence changes to users who currently have that contact's thread or conversation list open on screen (viewport-scoped presence subscriptions).
2026 messaging app development cost and build-vs-rent math
Under Eurostat (lc_lci_lev) statutory benchmarks, average hourly labor costs stand at €33.5 in the EU and €37.3 in the euro area, reaching €43.5 to €55+ in Western European hubs before senior engineering overhead and security tooling. In 2026, senior Central and Eastern European teams bill at $50 to $85 per hour, compared to $150 to $220 per hour for US metro agencies.
For how chat fits into a broader social network or creator platform budget, see our breakdown of social media app development cost and creator monetization platforms.
Build vs rent: when managed chat SDKs make sense
Renting a managed chat API (Stream Chat, Sendbird, or Pusher) lets you ship auxiliary marketplace, ride-share, or telehealth chat in three weeks for $400 to $2,500 per month based on Monthly Active Users (MAU). Building your own messaging core through a custom software development or product development partner wins when:
- Messaging is the core product or retention loop, and vendor rate limits, webhook latency, or rigid message schemas block your product roadmap.
- True End-to-End Encryption is required, since managed SaaS chat APIs terminate plaintext on their servers to index messages and fire server-side webhooks.
- Active scale crosses 50,000 to 100,000 MAU, where per-MAU SaaS overage charges exceed $8,000 to $15,000 every month, compared to a $600 to $1,200 monthly cloud bill for a dedicated Go, Rust, or Elixir WebSocket cluster.
Rent Sendbird or Stream if chat is a side feature in a marketplace MVP. Build your own WebSocket and SQLite sync engine if messaging is the reason users open your app, or if end-to-end encryption is part of your trust promise. You cannot bolt zero-knowledge cryptography onto a third-party plaintext SaaS later without a complete rewrite.
Implementation checklist: taking a messaging app to production
Before kicking off sprint one, verify that your technical specification answers these six architectural questions:
- Lock the idempotency and ordering contract: Generate RFC 9562 UUIDv7 or ULID keys on the client before queuing to the local SQLite outbox, and sort threads strictly by the server-assigned
conv_seqinteger rather than device clocks. - Isolate ephemeral state from durable storage: Route typing indicators and online heartbeats through in-memory pub/sub with short TTLs; persist only messages, reactions, and
last_read_seqwatermarks to your database. - Pick your encryption model on day one: Choose TLS + encryption at rest if you need server-side search and admin visibility; choose Signal X3DH + Double Ratchet for 1:1 and small private groups; choose IETF RFC 9420 MLS if encrypted groups must scale past 1,000 members.
- Architect the local database for locked-screen wakeups: Run on-device SQLite in WAL mode with FTS5 full-text indexing, encrypted via SQLCipher with the key stored under
AfterFirstUnlockThisDeviceOnlyin iOS Keychain / Android Keystore per OWASP MASVS v2.1. - Keep media bytes off the chat socket: Encrypt photos, voice notes, and videos on the client with ephemeral AES-256-GCM keys and upload directly to S3 or R2 via pre-signed URLs.
- Build App Store UGC moderation before submission: Implement single-tap user blocking, message-franking abuse reports, and new-thread rate limits to clear Apple App Store Guideline 1.2 and the EU Digital Services Act.

CTO and Co-founder at Idealogic. Directing engineering, systems architecture, security, and full-stack delivery across web, mobile, and blockchain.
Frequently asked questions
Building a production messaging app costs between $55,000 and $110,000 for a focused 1:1 and small-group MVP with offline sync, push notifications, and transport encryption. Adding Signal Protocol end-to-end encryption, multi-device key provisioning, voice notes, and a moderation console brings the budget to $120,000 to $220,000. Enterprise platforms supporting 10,000-member MLS encrypted groups and custom media pipelines start at $250,000.
A single-codebase mobile MVP built with React Native or Flutter takes 10 to 16 weeks when scoped to 1:1 chat, small groups, read receipts, APNs and FCM push wakeups, and SQLite offline storage. End-to-end encryption with multi-device key synchronization and out-of-band encrypted media attachments typically adds 6 to 10 weeks of specialized cryptographic and client storage engineering.
RFC 6455 WebSockets are the best default for general consumer and B2B chat because they work cleanly across web browsers, iOS, Android, and corporate firewalls. Choose MQTT when targeting ultra-low-power mobile connections or unstable cellular networks where lightweight binary headers and built-in QoS 1 delivery acks save battery. Use gRPC or HTTP/3 WebTransport when multiplexing binary streams between microservices.
Clients achieve effectively-once delivery over at-least-once network links by generating a globally unique, time-sortable ULID or UUIDv7 idempotency key on the device before the first send attempt. The client writes the pending message to its local SQLite outbox and reuses that exact ID on every retry. The server enforces a unique constraint on the message ID and safely deduplicates repeated frames.
The Signal Protocol uses X3DH session setup and pairwise Double Ratchet chains, which is ideal for 1:1 chats and small groups but scales poorly when group membership changes frequently because key updates scale linearly with member count. IETF RFC 9420 Messaging Layer Security (MLS) arranges group members in a binary TreeKEM ratchet tree, reducing key rotation complexity to logarithmic scale for groups of 1,000+ members.
Because the server only stores opaque ciphertext in an end-to-end encrypted chat app, server-side Elasticsearch or PostgreSQL full-text queries are impossible. Instead, each client device decrypts incoming messages locally and indexes the plaintext inside an on-device SQLite FTS5 virtual table encrypted with SQLCipher, storing the database master key inside the iOS Keychain or Android Keystore.
The server sends a push payload containing only the encrypted ciphertext blob or a wake token with the mutable-content flag enabled on Apple APNs or a high-priority data message on Android FCM. The mobile operating system wakes a background Notification Service Extension for a few seconds, which loads the ratchet state from shared keychain storage, decrypts the message locally, and renders the plaintext banner.
Rent a managed chat SDK like Stream or Sendbird when chat is a secondary feature inside a marketplace or telehealth app and you have fewer than 25,000 monthly active users. Build a custom messaging backend when messaging is your core product, when you require true end-to-end encryption where no third-party vendor holds plaintext, or when MAU-metered SaaS bills exceed $10,000 per month.
More from the journal

How to Build a Live Streaming App: Architecture and Cost
Glass-to-glass latency dictates every decision in live streaming app development: sub-500ms WebRTC for interactive stages, 2 to 4 second LL-HLS for 100k-viewer broadcasts, ABR transcoding ladders, sharded live chat, gifting ledgers, and 2026 infrastructure costs.

Predictive Maintenance Software: How It Actually Works
Predictive maintenance software ingests vibration, current, and thermal telemetry to forecast equipment failures across the P-F interval. Here is the ISO 13374 architecture, edge FFT feature extraction, RUL modeling, and CMMS work-order automation.

What Is a Smart Factory? IT/OT Architecture & Implementation Guide
Most Industry 4.0 pilots die in proof-of-concept purgatory because of point-to-point IT/OT integration spaghetti. Here is how to architect an event-driven smart factory using Unified Namespace, brownfield PLC gateways, and IEC 62443 network segmentation.