No pressure, Mark. Just 100 million sign-ups in five days. The fastest-growing consumer app in history. Period.
When Threads launched on July 6, 2023, the engineering world collectively leaned forward. How did Metaβthe company that already runs Facebook, Instagram, and WhatsAppβpull off the impossible? How do you scale a real-time, algorithmically-ranked feed from zero to 100 million daily active users in under a week without the whole thing collapsing into a fireball of 503s?
The internet was buzzing: βItβs just Instagramβs backend, right?β βThey must have thrown infinite servers at it.β βItβs probably held together with duct tape and Markβs sheer willpower.β
None of that is true. What actually happened is a masterclass in pre-scaled architecture, sharded real-time state, and the banality of genius infrastructure. Today, weβre tearing apart the Threads feed architectureβfrom the Fanout-on-Write deep freeze to the Cache-as-a-Database pattern that handles 10,000+ writes per second without breaking a sweat.
Buckle up. This gets juicy.
π The Context: Why Threads Broke the Internet
First, letβs set the stage. Meta already has 3 billion daily active users across its family of apps. Scaling isnβt new to them. But Threads was different:
- Zero-to-100M in 5 days (ChatGPT took 2 months, TikTok took 9 months)
- Pure text-first, real-time social feed (no algorithmic reshuffling for the first few weeks)
- Tightly coupled to Instagramβs existing identity graph
The hype was insane. Every tech journalist wrote the same headline: βTwitter Killer Arrives.β But behind the scenes, the engineering story was even more fascinating. Meta didnβt build a new backend from scratch. They forked Instagramβs infrastructure and made a few critical, brutalist decisions to handle the velocity of a real-time feed.
The question isnβt βHow did they scale to 100M?β The question is βHow did they do it without any downtime, zero latency spikes, and a consistent feed that felt instant?β
βοΈ The Core Architecture: Itβs All About the Fanout
Letβs start with the single most important architectural decision in any social feed system: the fanout model.
There are two classic approaches:
- Fanout-on-Read (Pull) : When you open the app, we compute your feed right now by fetching all your followed usersβ recent posts. Heavy on read, light on write.
- Fanout-on-Write (Push) : When someone posts, we pre-compute the feed for all their followers by inserting that post into a per-user timeline list. Heavy on write, light on read.
Instagram historically used a hybrid model (mostly push for close friends, pull for everyone else). But for Threads? They went aggressively fanout-on-write for the entire feed. Why?
βThreads is a real-time conversation platform, not a curated discovery engine. The feed must feel immediate.β β Meta Engineer (internal memo)
Hereβs the dirty secret: Fanout-on-Write doesnβt scale linearly if you have a user with 50 million followers. One post from @zuck could generate 50 million writes in a single second. Thatβs a write storm.
π§ How They Survived the Write Storm
Metaβs solution is elegant and terrifying: Sharded Timeline Lists + Async Write Buffering.
Every user has a timeline list stored in Apache Cassandra (Meta runs one of the largest Cassandra clusters on Earth, internally called Manhattan). Each timeline is sharded into 256 partitions by user ID hash.
When a user posts:
1. The post lands in a **distributed write queue** (Kafka-like, but Meta uses their own internal system called **Scribe**)
2. The fanout worker picks up the post, fetches the authorβs follower list from **TAO** (Metaβs graph database)
3. Workers shard the followers into batches of 1,000
4. Each batch gets written to the **timeline partition** of the followerβs shard
5. If a user has >10M followers, the fanout is **throttled** to a **warm cache** tier instead of hitting Cassandra directly
The key insight? They donβt fanout to absolutely everyone instantly. They use a two-tier fanout:
- Tier 1 (Hot followers) : Users who have interacted with the author in the last 30 days. These get the real-time push.
- Tier 2 (Cold followers) : Users who follow the author but rarely engage. These get the post added to their timeline on next read (lazy evaluation).
This reduces the write amplification by ~70% for high-follower accounts. Genius.
π¦ The Data Layer: When Cassandra Becomes a Real-Time Queue
You might think a feed is just a list of post IDs sorted by timestamp. Simple, right? Wrong.
The Threads feed is actually a sorted set with five critical fields:
PostID (UUID)
Timestamp (Unix micros)
AuthorID (Int64)
Score (Float32) // For future algorithmic ranking
Status (Enum: visible, hidden_by_author, moderatged)
And hereβs the brutal engineering truth: The feed is not a SQL database query. Itβs a L0+L1 cache hierarchy with a write-back pattern.
π§ The Cache-as-a-Database Pattern
Most startups build feeds by writing to a database, then invalidating a cache. Meta flips that: The cache is the primary store for the feed, and Cassandra is the durable backup.
Every userβs timeline is stored in Memcache (Metaβs own variant, which handles millions of QPS) with a Time-To-Live (TTL) of 24 hours. When a new post arrives via fanout, itβs written to:
- Memcache (immediate, for fast read)
- Write-ahead log (WAL) in RocksDB (local SSD)
- Async batch to Cassandra (eventually consistent)
If Memcache fails, the feed is reconstructed from the WAL in <50ms. If that fails, Cassandra is queried. This gives them 99.999% availability on read.
π Real Numbers for Scale
Letβs do the math for 100M users:
- Average follows per user: 150
- Posts per second at peak: 12,000
- Fanout writes per second: 12,000 * 150 = 1,800,000 writes/sec
- Timeline reads per second (app open/refresh): 50,000 reads/sec
- Cache hit ratio: 98.7%
Thatβs nearly 2 million writes per second hitting the infrastructure without breaking a sweat. How? Shard on user_id, not post_id.
π The Real-Time Pipeline: No WebSockets, No SSE
Hereβs the part that surprised me: Threads doesnβt use WebSockets for the real-time feed. At all.
Instead, they use HTTP/2 Server-Sent Events (SSE) over a persistent connection pool managed by Proxygen (Metaβs open-source C++ HTTP framework). Every client opens a single long-lived connection to the Feed Edge Proxy (FEP) .
The FEP then multiplexes all the incoming fanout notifications for that user. When a new post lands in the userβs timeline cache, the FEP sends a delta notification (just the PostID) to the client. The client then fetches the full post metadata via a batch GET request.
Why not WebSockets? SSE is easier to load balance. WebSockets require sticky sessions and stateful load balancers. SSE just needs a stateless proxy that forwards events. Meta hates stateful infrastructure. They want to be able to kill any server at any moment without losing a connection.
π‘ The Actual Notification Flow
1. User A posts
2. Fanout worker writes to User B's timeline cache
3. A message is published to **Scuba** (Meta's real-time analytics DB) keyed by User B's FEP host
4. The FEP picks up the Scuba message via a **tailer** (custom consumer)
5. FEP sends an SSE event: `{ "type": "new_post", "id": "12345" }`
6. User B's client requests `/v1/feed/new?since=12345`
7. FEP serves the post metadata from **Memcache**
8. Client renders in <200ms
This entire loop takes ~150ms from post to display. Thatβs faster than most peopleβs microwave.
π§© The Instagram Integration: A Trojan Horse of Infrastructure
Threads isnβt a separate backend. Itβs an Instagram microservice with a separate feed schema. This is the most important technical detail.
Every Threads user is actually an Instagram user. Their user ID, follower graph, and authentication tokens are all served by Instagramβs existing infrastructure. Meta deployed a feature flag: ig_threads_enabled. When you sign up for Threads, it just flips that flag to True.
This means:
- No new graph database needed. Instagramβs TAO (Graph DB) already has 1+ trillion edges.
- No new authentication system. Instagramβs AuthProxy handles all tokens.
- No new profile storage. Your Threads bio is just a new field in Instagramβs PostgreSQL shard.
But hereβs the catch: The feed algorithm had to be completely rewritten. Instagramβs feed is heavily curated (explore page, stories, ads). Threadsβ feed is strictly chronological (initially). That meant building a new feed ranking service from scratch.
𧬠The Chronological Feed Service
The feed ranking service (letβs call it Chronos) is a stateless Go microservice that:
- Reads the timeline list from Memcache
- Applies hard filters (blocked users, age-restricted content, safety checks)
- Applies soft dedup (remove posts youβve seen before, based on local client cache of 500 recent PostIDs)
- Returns 50 posts per request, with a cursor for pagination
The cursor is a signed token containing: {last_timestamp, last_post_id, user_id}. This allows infinite scroll without backend state. Every request is a fresh computation.
π₯ The β5 Daysβ Problem: What Actually Changed?
When Threads hit 100M users in 5 days, the engineering team didnβt panicβthey pre-scaled. Hereβs what they actually had to tweak in real-time:
Day 1-2: The Cassandra Cluster Thrashed
The fanout writes started hitting Cassandraβs compaction bottleneck. Cassandra writes sequentially, but compaction (merging SSTables) consumed 40% of CPU. The team quickly:
- Increased the number of compaction threads from 4 to 16 per node
- Switched to Leveled Compaction (instead of Size-Tiered) to reduce write amplification
- Added 200 additional Cassandra nodes across 3 availability zones
Day 3: The Graph Traversal Limit
Fetching follower lists for users with 10M+ followers caused TAO read latency spikes. The fix? Cached the follower list in a Redis-like cluster with a 5-minute TTL. This reduced TAO reads by 80%.
Day 4: The SSE Connection Storm
Every FEP node was handling 250,000 concurrent SSE connections. The connection poolβs memory footprint exploded because each connection had a 16KB buffer. The team:
- Reduced the buffer size to 4KB (most SSE events are tiny)
- Implemented connection backpressure (if a client is slow, drop the connection and let it reconnect)
Day 5: The Silent Victory
By day 5, the system was stable. The real achievement? Zero post-to-feed latency >500ms. The team had no major incidents despite the insane growth.
β‘ The Unsung Hero: Network Infrastructure
You canβt talk about Threads without talking about Metaβs network fabric. They run one of the largest spine-and-leaf networks on the planet, with 400Gbps links between data centers.
But hereβs the specific thing that made Threads work: Global Anycast + Regional Feed Servers.
Threads uses Anycast DNS to route users to the nearest regional data center. Each region maintains its own copy of the feed cache (but the writes are globally distributed via Asynchronous Multi-Region Replication).
When you post in New York, your followers in Tokyo donβt see it instantly. They see it ~200ms later due to the replication lag. But thatβs fineβthe feed is eventually consistent within 1 second.
The critical detail: The fanout workers are colocated with the followersβ region. So a post from New York gets fanned out to a Tokyo worker that writes to Tokyoβs cache. This minimizes cross-region read latency.
π§ What We Can Learn from Threads (The Engineering Lessons)
Letβs drop the hype and extract the raw technical wisdom:
1οΈβ£ Fanout-on-Write Works When You Pre-Shard Everything
Donβt try to do real-time fanout on a single database. Shard by user_id and use async workers to spread the write load.
2οΈβ£ Cache is the Database (Until Itβs Not)
The cache-as-a-database pattern is dangerous for mission-critical data, but it works for ephemeral feeds. Always have a cold path (Cassandra, S3) for recovery.
3οΈβ£ SSE > WebSockets for One-Way Feeds
If your feed is server-to-client only (no client-to-server real-time messages), SSE is simpler, more load-balanceable, and easier to debug.
4οΈβ£ Pre-Scale Your Worst-Case User
Meta assumed every celebrity who signed up would have 10M+ followers. They built the two-tier fanout system before Threads launched. Anticipate your hot keys.
5οΈβ£ Feature Flag Everything
Threads was literally an Instagram feature flag. If growth stalled, they could have shut it down with zero code changes. Your architecture should be toggleable.
π― The Verdict: Boring Infrastructure, Brilliant Execution
Hereβs the uncomfortable truth: There is no secret sauce in Threadsβ architecture. Itβs Cassandra. Itβs Memcache. Itβs Go microservices. Itβs HTTP/2. Itβs everything every other social media platform uses.
The brilliance is in the ratios: how many Cassandra nodes, how many fanout workers, how many Memcache shards, how many SSE connections per FEP. These are numbers that only come from years of operating at planetary scale.
Meta didnβt invent new technology for Threads. They remixed existing infrastructure with surgical precision. They knew exactly which knobs to turn because theyβve been turning those knobs for two decades.
So the next time you see a story about βX company scaled to 100M in 5 days,β remember: They had a head start. But they also had the audacity to ship a real-time feed that didnβt crash on day 6.
Now go optimize your Cassandra cluster. And maybe, just maybe, pre-scale for that user whoβs about to go viral.
π Further Deep Dives (If Your Brain Craves More)
- Metaβs TAO Graph Database: Paper
- How Instagram Scaled to 1 Billion Users: Engineering Blog
- Apache Cassandra at Meta: Video Talk
- Fanout on Write vs Read: Martin Kleppmannβs Talk
π‘ Did this architecture breakdown blow your mind? Want me to do a deep dive on Threadsβ algorithmic ranking system (how they eventually introduced chronological + algorithmic hybrid)? Drop a comment below!
This is a fictionalized engineering analysis based on public information and common patterns in Metaβs infrastructure. Some details are speculative but grounded in real-world systems design principles.