# Design Slack Mobile: Channels, Threading, and Presence

Source: https://www.techinterview.org/post/3233474989/design-slack-mobile-channels-threading/
Updated: 2026-07-26 · techinterview.org

Slack on mobile is harder than chat. [Chat apps](/post/3233474372/system-design-design-discord-voice-text-channels-server-architecture-webrtc-permissions-bots-real-time-presence/) have one thread per conversation. Slack has channels with threads inside channels, with reactions on threads, with shared channels across workspaces, with files attached to messages. The interview tests whether you can handle hierarchical, partially-loaded data on a constrained device.

## Functional requirements

- **Multiple workspaces per user.** Each workspace is its own island — separate channels, members, and auth token. Interviewers probe how the client switches workspaces without re-downloading everything, so scope the local datastore per workspace and keep boot state cached for each.

- **Channels (public, private, DM, group DM).** Each type carries different membership and visibility rules, which decide who receives a message and who can search it. Expect a question on how a new message reaches every member's device in real time — the same [fanout-on-write versus fanout-on-read](/post/3233474168/system-design-twitter-news-feed-timeline-fanout-on-write-fanout-on-read-celebrity-problem-ranking-caching/) tradeoff behind a news feed.

- **Threads within channels.** The mobile trap is that a reply can arrive over WebSocket for a thread you have not opened, so the local store must attach it to the right parent and bump the reply count without fetching the whole thread. Be ready to explain how you keep the "N replies" indicator correct while offline.

- **Reactions, file attachments, link unfurls.** Reactions are tiny, high-frequency events — batch and coalesce them rather than re-rendering per tap. Files upload separately and the message holds only a reference, while unfurls are resolved server-side so the client just renders the returned preview.

- **Presence indicators.** Presence is best-effort, not durable state — a green dot can be stale for a few seconds and that is acceptable. Interviewers want to hear that you batch updates and only track presence for users actually on screen, not every member of a 10,000-person channel.

- **Search across all messages.** This runs server-side over an inverted index because the phone holds only a slice of history locally. Be clear that the client is a thin pager over the search API, with results scoped to exactly the channels the user can access.

- **Unread badges per channel.** The count is derived from a per-user `last_read` timestamp compared against message timestamps, computed locally so badges update instantly. The hard part is reconciling that local count with the server after the user reads on another device.

## Architecture

The client maintains a **local datastore** (SQLite) of channels, messages, threads, and users. A **WebSocket connection** (Slack uses Real-Time Messaging / Events API) streams events. A **REST API** handles initial loads, search, and bulk operations.

## Channel model

Channel has a `last_read` timestamp per user. Unread count = messages where `ts > last_read`. The mobile client maintains this locally and syncs to server on read events.

## Threading

A thread is a parent message + replies. Replies have `thread_ts` equal to the parent's `ts`. Mobile UI shows the parent in the channel and a "N replies" indicator. Tap to open the thread; replies are fetched on demand.

## Sync strategy

Three layers of sync:

- **Workspace boot:** initial REST call returns user, channel list, and recent activity.

- **Channel open:** fetch the last ~50 messages on demand. Pagination as the user scrolls up.

- **Real-time:** WebSocket pushes new messages, edits, deletions, and reactions.

## Presence

Presence is volatile. Server tracks active sockets per user. Pushed via WebSocket. Mobile app shows green dot for active users in DMs and channel sidebar; updates batched to avoid UI thrash.

## Push notifications

Server-side rules decide who gets a push (mentions, DMs, keyword matches). Push payload is opaque — content-available + a fetch trigger. App fetches the actual message and renders the notification with content. This protects user privacy but increases push latency.

## Search

Server-side full-text search over all messages the user has access to. Results paginated, with snippets. Mobile UI is a thin client over the search API.

## Storage budget

Local SQLite is bounded — keep recent messages per channel (last 7 days or 100 messages, whichever is more). Older messages are paged on demand. The user's starred and threaded messages are kept indefinitely.

## Frequently Asked Questions

### Why is Slack mobile sometimes slow to show new messages?

Background WebSocket reconnect can take seconds. iOS background app refresh policies limit how aggressively the app can stay connected. Push notifications wake the app and trigger a fetch.

### How are file attachments handled?

Files are uploaded separately to S3-backed storage; the message references the file ID. Mobile downloads thumbnails on demand and full files on tap. Encrypted at rest in some compliance tiers.

### How does Slack handle very large channels?

Server-side pagination, virtualized scroll on the client, lazy-loaded user metadata, and aggressive culling of old messages from the local DB.
