How to build an app like Slack: Real-time messaging architecture and real costs

Key Takeaways

  • Real-time messaging at scale requires WebSocket connections per user - Slack maintains over 5 million simultaneous WebSocket sessions at peak. Planning your WebSocket server architecture before you write the first message handler is critical.

  • Message ordering is the subtle hard problem. Two users sending messages simultaneously in the same channel must see them in the same order. Without a distributed sequencing mechanism, you get race conditions that corrupt conversation history.

  • A basic team messaging MVP (channels, direct messages, file sharing, notifications) takes 14-20 weeks and costs $120,000-$200,000.

  • Search is its own engineering project. Full-text search across message history requires a dedicated indexing service - Elasticsearch or OpenSearch. Plan 4-6 weeks and 20-25% of total build cost for search alone.

  • Presence (online/away/offline status) looks simple and is architecturally complex. Slack uses dedicated presence servers separate from the messaging infrastructure.

Most developers who want to "build an app like Slack" start by building a chat UI. That's the easy part. The hard part is building the infrastructure that ensures every user in a channel sees messages in the same order, within 500 milliseconds, even when 10 people are typing simultaneously.

Slack maintains over 5 million simultaneous WebSocket connections at peak weekday hours. Their infrastructure delivers messages across the world in under 500ms. That's not a simple WebSocket server running on a $20/month VPS.

This post covers the actual architecture decisions, the four hardest engineering problems, and realistic cost and timeline estimates for a team messaging application.

What "build an app like Slack" actually means

Before getting into architecture, define your scope. "Like Slack" covers a wide range.

Minimum viable messaging app:

  • Channels (public and private)

  • Direct messages

  • File uploads

  • Push notifications

  • Web client

  • Basic search

Full-featured team communication tool:

  • Thread replies (the hardest UI problem Slack has)

  • Presence (online/away/offline)

  • Message reactions

  • Rich text formatting with code blocks

  • Slash commands

  • Integration framework (webhooks, apps)

  • Full-text search across message history

  • Admin controls, SSO, and audit logs

The cost and timeline difference between these two is significant. Build the MVP first, then expand. Don't try to ship threads and an integration framework in version one.

The core architecture

A Slack-like application needs five primary services, each with distinct scaling characteristics:

1. WebSocket gateway

This is the most performance-critical piece. Every connected client maintains a persistent WebSocket connection to receive messages in real-time. Slack's architecture uses dedicated gateway servers - stateful servers that maintain user connection information and channel subscriptions in memory.

The key design decision: gateway servers are stateful. A user connected to Gateway Server 3 will receive messages routed through Gateway Server 3. Your message broker (Redis pub/sub or Kafka) needs to know which gateway server holds each user's connection to route messages correctly.

For low scale (under 10,000 concurrent users): a single Node.js or Go WebSocket server with Redis pub/sub works well.

For high scale: You need a load balancer that routes users to gateway servers using sticky sessions, a message broker (Kafka) that distributes messages across gateway servers, and horizontal scaling on the gateway layer.

2. Message store

The persistent database that holds all messages. PostgreSQL is the standard choice - it handles message history queries well, supports JSONB for message metadata, and scales to hundreds of millions of messages with proper indexing.

Schema essentials:

  • Messages table (id, channel_id, user_id, content, created_at, thread_parent_id)

  • Channels table (id, workspace_id, name, type, created_at)

  • Channel memberships (user_id, channel_id, last_read_at)

  • Workspaces table

The last_read_at per user per channel is how you power unread counts. Every time a user opens a channel, their last_read_at updates. Messages with created_at > last_read_at are unread.

3. Message ordering service

This is the subtle hard problem that most early messaging apps get wrong.

When two users send messages to the same channel within milliseconds of each other, which message appears first? On a single server, it's insertion order. On a distributed system, it depends on which server received which message first - which introduces race conditions.

Slack uses a distributed sequence number generator for each channel, built on their channel server infrastructure. Every message gets a monotonically increasing sequence number within its channel. All clients sort by sequence number, not by timestamp.

For your implementation: either route all messages for a given channel through a single "channel server" (simplest), or use a distributed sequence generator like Twitter's Snowflake ID approach. Do not rely on created_at timestamps for ordering - clock skew across servers will corrupt conversation history.

Full-text search across message history is a standalone engineering project. You cannot do this with a SQL LIKE query - it won't scale past a few hundred thousand messages.

The standard approach: an Elasticsearch or OpenSearch cluster that indexes every message as it's written. Queries against the index return matching messages with their channel and workspace context.

The hard parts:

  • Keeping the search index in sync with the message store (use a Kafka consumer that writes to Elasticsearch)

  • Returning results in the correct permission context (a user can only see messages from channels they're a member of)

  • Handling message edits and deletions in the index

Budget 4-6 weeks and a dedicated engineer to implement production search. It's 20-25% of total build effort.

5. Presence service

Presence - the green/yellow/red dot next to each user's name - looks trivial and is architecturally complex.

Slack uses dedicated presence servers that are separate from the messaging infrastructure. They track user connections and broadcast presence changes to the channels the user is a member of.

The challenge: how do you know when a user goes offline? You can't rely on them sending a "disconnect" message - browsers crash, network connections drop, phones die. The standard approach is a heartbeat - each client sends a ping to the presence server every 30 seconds. If 90 seconds pass with no ping, the user is marked offline.

At scale, broadcasting presence changes to all members of all channels for all users creates a lot of events. Optimize by only broadcasting presence to members who have recently viewed a channel (within the last 24 hours), not all historical members.

The four hardest problems

1. Message ordering under concurrent writes. Already covered above. Design your channel sequence number system before writing message handlers. This is not recoverable after you have production data with ordering conflicts.

2. Offline message delivery and catch-up sync. When a user opens Slack after a weekend away and has 200 unread messages across 15 channels, the application needs to efficiently deliver those messages without overwhelming the client or the server. Implement incremental sync with cursor-based pagination, not "fetch all unread messages" queries.

3. Thread rendering. Thread replies are the most complex UI feature in a messaging application. A message in a channel can have a thread of replies. The main channel shows a "reply" indicator but not the replies themselves. The thread panel shows the parent message plus all replies. Both the channel view and the thread panel must stay in sync when new replies arrive. The data model is straightforward (thread_parent_id on the messages table). The UI synchronization logic is not.

4. Large workspace performance. When a workspace has 5,000 members and a channel has 2,000 members, loading the channel's member list for presence purposes creates expensive queries. Implement lazy loading for member lists and presence data - only load presence for users visible in the current view.

Build costs and timeline

Option 1: MVP messaging platform (web only)

Core features: channels, DMs, file uploads, notifications, basic search

Timeline: 14-18 weeks Team: 2 senior backend engineers, 1 frontend engineer, 1 designer Cost: $120,000-$175,000

Post-launch infrastructure: $2,000-5,000/month at moderate scale

Option 2: Full team communication tool

Core + threads, presence, rich text, slash commands, admin panel, SSO, mobile app (iOS + Android), advanced search

Timeline: 24-32 weeks Team: 3 senior backend engineers, 2 frontend engineers, 1 mobile engineer, 1 designer Cost: $250,000-$420,000

Post-launch infrastructure: $5,000-15,000/month

Option 3: Use an embedded chat SDK

If you need messaging inside your product (not a standalone messaging app), don't build from scratch. Stream, Sendbird, and CometChat provide messaging infrastructure as a service. You get WebSocket management, message persistence, presence, and push notifications in exchange for a monthly fee that scales with monthly active users.

Stream starts at $399/month for up to 10,000 MAU. At 100,000 MAU, you're looking at $1,500-$3,000/month depending on features. For most products where messaging is a feature rather than the core product, this is a much better value than building from scratch.

Build from scratch when: messaging is your core product and the economics of ownership beat the licensing cost at your expected scale, or when you have compliance requirements (healthcare, finance, defense) that prevent you from using third-party messaging infrastructure.

Technology stack recommendations

Backend:

  • WebSocket server: Go or Node.js (Go for higher concurrency efficiency)

  • Message broker: Kafka (durable, ordered, reliable) + Redis (pub/sub for real-time fan-out)

  • Message store: PostgreSQL (transactions, JSONB, mature tooling)

  • Search: Elasticsearch or OpenSearch

  • File storage: S3 or compatible object storage

Frontend:

  • Web: React with a WebSocket client library (Socket.io or native WebSocket)

  • Mobile: React Native for cross-platform, or Swift/Kotlin for native

Infrastructure:

  • WebSocket servers: stateful, need sticky sessions (use AWS ELB or nginx with consistent hashing)

  • Message store: RDS PostgreSQL with read replicas for message history queries

  • Elasticsearch: managed (AWS OpenSearch Service) to avoid cluster management overhead

The decision most teams skip

Before building, answer this question: Is messaging the core of your product, or a feature that supports the core?

If messaging is a feature (you're building a project management tool that needs team chat, or a marketplace that needs buyer-seller communication), use Stream or Sendbird. You'll pay $500-$2,000/month and ship in 4 weeks instead of 6 months.

If messaging is the product (you're building a team communication tool, a community platform, or a specialized communication application for a specific industry), build custom. The IP is yours, the architecture fits your use case, and you're not paying per-MAU licensing fees forever.

The teams that get in trouble are the ones that decide to build custom to "save money" on licensing fees without fully pricing in the engineering cost, timeline, and ongoing maintenance of a real-time messaging system.


Building a real-time communication product or platform? 1Raft has shipped SaaS platforms and real-time applications across multiple industries. See our SaaS platform engineering service or talk to us about your architecture.

Frequently Asked Questions

A basic team messaging app (channels, direct messages, file uploads, push notifications, web + mobile) costs $120,000-$200,000 and takes 14-20 weeks with a senior engineering team. An enterprise-grade messaging platform with thread-level organization, real-time presence, full-text search, admin controls, SSO integration, and audit logging costs $250,000-$450,000 and takes 24-36 weeks. Infrastructure costs post-launch run $3,000-$15,000/month at small to mid scale, primarily driven by WebSocket server capacity and message storage.

The standard stack for a Slack-like application in 2026 is Node.js or Go for the WebSocket server (Go handles concurrent connections more efficiently at scale), Redis for pub/sub and presence state, PostgreSQL for the persistent message store, Elasticsearch or OpenSearch for full-text search, S3-compatible storage for file uploads, and React or React Native for the client. For the WebSocket layer specifically, consider Phoenix (Elixir) if you expect very high concurrent connections - it handles 2 million+ connections per server node.

The three hardest problems are message ordering (ensuring all clients see messages in the same sequence even under concurrent writes), presence at scale (tracking online/away/offline status for millions of users without polling), and search (indexing billions of messages for sub-second full-text retrieval). Most teams underestimate all three. Message ordering requires distributed sequence numbers or vector clocks. Presence requires dedicated infrastructure separate from the messaging layer. Search requires Elasticsearch or equivalent, not a SQL LIKE query.

When a user is offline, messages must be queued and delivered when they reconnect. The standard approach is a message queue (Kafka or RabbitMQ) that stores undelivered messages with delivery confirmation receipts. When a user reconnects, their client requests messages since their last-seen timestamp. Push notifications (APNs for iOS, FCM for Android) handle waking the mobile app when messages arrive. The edge case to plan for is large catch-up syncs when a user has been offline for days - rate limiting and incremental sync logic prevent this from overwhelming the client.

Using Slack's API means building on top of Slack's infrastructure - apps, bots, and workflow automations that live inside Slack workspaces. Building a Slack alternative means building everything Slack provides - the messaging infrastructure, the workspace model, the client applications, the admin system. The decision is whether you need a messaging platform embedded in your product (use Slack API or Stream, Sendbird, etc.) versus building your own communication product (custom build). Custom builds make sense when messaging is your core product, when compliance requirements prevent third-party data handling, or when your workflow is fundamentally different from Slack's workspace model.

Sharing is caring

Insights from our team