Scope, then retention
Scope the product first, because the messaging apps you know are cousins rather than twins.
Take the standard set: one-to-one chat, group chat, delivery and read receipts, presence, and offline delivery. Then settle retention up front, because one app historically deleted messages from its servers once delivered while another sells searchable history forever, and that single requirement changes your storage design completely.
Run the numbers for a mid-sized app. Fifty million daily users sending 40 messages each is 2 billion messages a day, which across 86,400 seconds is about 23,000 a second on average and maybe 70,000 at the evening peak.
Notice each message is small, a few hundred bytes with its metadata, so your peak write bandwidth is around 20 megabytes a second. Storage at 200 gigabytes a day is 73 terabytes a year before replication, real but manageable.
The number that shapes everything
Look at the number that actually shapes the system: concurrent connections. If a fifth of your daily users are online at peak, that is 10 million sockets open at once.
A well-tuned server holds hundreds of thousands of them, and one famous deployment demonstrated over two million per machine. So you need a fleet, and more importantly a way to find which machine holds which person.
Take that as the thing making chat harder than a stateless API: connection state.
Keep your latency requirements strict but local. Sender to recipient in under a few hundred milliseconds feels instant. Ordering must hold inside a conversation, and nobody cares about a global order.
Deliver at least once with deduplication on the client, because dropping a message is the one sin a chat app cannot commit.
Worked example
Leah is sizing chat for a dating app with 8 million daily actives. Messages are easy: 8M users x 25 messages is 200M a day, about 2,300 per second, one Cassandra cluster shrugs. Connections are not. Product wants the app to receive messages while backgrounded, which on the web client means a live WebSocket for every open tab. She measures 15 percent peak concurrency, 1.2 million sockets. Load testing a 16 GB Node server shows memory pressure at 300,000 idle connections, mostly per-socket buffers, so she plans 6 connection servers plus 2 for failover headroom. Her design review headline: the message pipeline is a rounding error, the socket fleet and its session registry are 80 percent of the infrastructure.