System design interview guide
Instagram Feed System Design
You post a Reel on spotty LTE. The app says "posted" in two seconds—but playback stutters because only a poster frame exists while the full bitrate ladder is still encoding. Your friend's feed still shows yesterday's order because fan-out is backed up. Instagram-shaped interviews grade media pipeline + hybrid feed together: upload ack is not full transcode, and an influencer post cannot fan out to fifty million mailbox writes.

Problem statement
You are designing an Instagram-class home feed: photos and Reels from people you follow, media upload with async transcoding, ranking or recency, optional Stories, and CDN delivery on mobile. Functionally you need media post, following feed read, likes, optional Stories TTL, and profiles. Non-functionally you need roughly sub-300 ms feed p95 for metadata, media start under a few seconds, high availability, and honest processing states when encodes lag. Scale sits at hundreds of millions of daily actives with reads crushing writes, heavy CDN egress, and a few creators whose follower counts make naive fan-out a cost incident. What interviewers reward: metadata-fast / bytes-async split; hybrid fan-out; mailboxes of IDs separate from post bodies; bounded candidates and ranker timeouts; post ack before full transcode ladder; degrade ranking and media honestly—not blank screens.
Introduction
You post a Reel on spotty LTE. The app says "posted" in two seconds—but playback stutters because only a still image exists while video finishing is still running. Your friend's feed still shows yesterday's order because catch-up to followers is backed up. Same product, three clocks: posted (the app said OK), video processing (playable quality ready), feed catch-up (friends can see it in their scroll).
"Design Instagram's feed" means: scroll a stream from people you follow, upload photos and video that become visible worldwide, and keep each swipe cheap—never ship full-resolution video inside every API response.
Most interviews focus on Home (often Stories). Explore is optional unless they widen scope in clarifying questions.
Interviewers grade two lanes that a text-only feed interview may skim:
- Light — who posted what, order, permissions, a short list of post IDs.
- Heavy — where bytes live, when video becomes playable, CDN URLs, and cost of shipping media.
The feed is not one SQL join. It is pointers plus background work (push to followers, finish video, notify)—and skew: many scroll, few post, a few creators are huge.
Weak answers ship full video in the feed JSON or block "posted" until every quality is done. Strong answers cap how many posts you consider per swipe, bound ranking time, return a processing state when video is not ready, and say what the UI shows when media or the CDN lags.
If you remember one thing: Light path fast; heavy bytes async—never block post success on every video quality finishing.
If this is your first time, go to Board path below—come back to this intro after one mock.
Board path (first read, ~10 min)
Start here if you have never designed an Instagram-style feed. Finish this section, then stop and try a short mock. Queue brands, celebrity fan-out math, and playback details live in After one mock.
What problem are we solving?
A creator uploads a Reel. The product must answer three different “done?” questions:
- Posted — Did we accept the upload and save the post?
- Video processing — Is something playable yet (even if more qualities arrive later)?
- Feed catch-up — Can followers see it when they scroll?
Wrong answers look like: the app hangs until every video quality exists, or the scroll API returns giant video bytes, or a celebrity post tries to write into every follower’s mailbox in the HTTP request.
What to write on the board (start simple)
- Two lanes — Light (post metadata, order, permissions) vs heavy (media bytes, finishing video, CDN links).
- Three clocks — Posted ≠ video ready ≠ visible in every follower’s feed.
- Upload — Save the blob and a durable post row; return success before every quality is ready; show a processing state if needed.
- Scroll — Load a capped list of candidate post IDs → fetch light metadata → attach media URLs → filter blocks → rank under a time budget → return a cursor for the next page.
- Huge creators — Don’t pretend one write updates every follower’s list in the request; say “normal authors vs mega-creators” and park the hybrid policy for after the mock.
That’s the first board. Tool and protocol names come after this mock.
Clarifying questions (say these in the room)
You: “Is this Home from people I follow only, or do we also need Explore discovery in the same round?”
Interviewer: “Home feed from follows; Explore can stay out of scope unless we expand.”
That keeps you on follows + media, not a full “for you” recommender on day one.
You: “When the app says posted, does that mean the file is saved, or every video quality is finished?”
Interviewer: “Users expect fast ack; quality can land later.”
Checkpoint: Write “posted ≠ playable.” Return a processing state when video is not ready yet—don’t empty the card, don’t block success on finishing every quality.
You: “Should creators with tens of millions of followers be a special case?”
Interviewer: “Yes—call out celebrity fan-out explicitly.”
You owe a different catch-up path for mega-creators—not “write to everyone” in one shot.
You: “Are Stories in scope—short-lived, separate from main posts?”
Interviewer: “Yes, mention expiry; keep ranking shallow unless we push.”
Stories need a clear time-to-hide—not “posts with a flag.”
You: “I want to leave Explore, DMs, payments, and training a ranking model out of scope so we can focus on upload, home scroll, and degradation. Does that match?”
Interviewer: “Yes—focus on home feed and media at scale.”
What you can say out loud (next to the board)
- Clocks: “I’d separate posted, video ready, and when followers’ feeds catch up.”
- Lanes: “Light metadata on the hot path; heavy bytes and finishing video in the background.”
- Upload: “Save durable post + blob, ack fast, show processing until playable.”
- Scroll: “Cap candidates, hydrate metadata, attach media URLs, rank under a timeout, return a cursor—never put video bytes in the feed JSON.”
First-pass: what should stick
- Three clocks — Posted, processing, feed catch-up are different promises.
- Two lanes — Light metadata vs heavy media; don’t mix them on one path.
- Cheap scroll — Cap work per swipe; never inline full video in the API response.
End of first pass
⏸ End of first pass — stop scrolling.
Practice clarifying questions and this board now. Do not continue into celebrity fan-out math, capacity, or media-pipeline depth until you’ve done a short requirements mock.
Ready for depth? Only then open After one mock.
After one mock
Return to Board path if this is your first read.
Everything below is for after one mock—or when the interviewer pushes on hybrid fan-out, transcode ladders, CDN egress, ranking timeouts, and production failure modes.
How to approach
Clarifying questions for the requirements stage live in the Board path. After that mock, deepen with capacity, then walk one Reel upload and one feed page before you debate store brands.
Teaching aside: A Facebook feed interview often centers on fan-out and ranking over text-heavy posts. Instagram adds upload resume, transcode queues, variant URLs, and CDN egress as first-class costs. If you only reuse a news-feed diagram without a media lane, you miss half what the room is grading.
Minute pacing (about 45–60 minutes)
| Minutes | Focus |
|---|---|
| 0–5 | Clarify Home vs Stories vs Explore, post ack vs transcode, celebrities, out of scope |
| 5–12 | Capacity: read:write skew, egress, one celebrity fan-out estimate |
| 12–25 | Write path: upload → durable post → async transcode + fan-out |
| 25–40 | Read path dig: candidates, hydrate, CDN URLs, rank, cursor |
| 40–50 | Architectural dig (ack vs ladder) + one production scene |
| 50–60 | Questions / deepen one tradeoff |
If this is your first Instagram-feed design, spend minutes 0–12 only on the Board path. Queue brands and playback detail wait until after one mock.
In the room (say-aloud lines — fuller depth after Board path):
- “I split light metadata from heavy media.”
- “Upload: durable blob + post row; HTTP success does not wait for every quality.”
- “Scroll: capped candidates → hydrate → CDN URLs → rank under a timeout → opaque cursor.”
- “When processing lags, return posts with processing states—not empty cards, and never video bytes in the feed JSON.”
Out of scope (and why you park these)
Write a short out-of-scope list on the board so the interviewer sees you can bound the problem.
Full Explore / For You retrieval stack. Explore is offline candidate generation plus online rerank over a huge pool—not the same mailbox fan-out as follows. Note "Explore injects candidates elsewhere" without designing the full recommender unless they expand scope.
Direct messages and calling. Real-time messaging is a chat-shaped problem (per-thread order, delivery receipts). Park it unless asked.
Training the ranking model end to end. You need the serving interface: bounded candidates in, scores out, timeout behavior. Feature-store plumbing is a different interview.
GPU beauty filters and AR effects. Client-side or async offline—off the post ack critical path.
Strongly consistent worldwide visibility the millisecond someone posts. Home feed accepts short lag. Promise instant global mailbox sync and you invent a harder problem than the room asked for.
Capacity estimation
Before you draw architecture boxes, use rough numbers so you do not promise impossible per-scroll work or ignore egress.
| Dimension | Rough scale | What this means for your design |
|---|---|---|
| DAU | 100M+ (varies by region) | Home reads dominate; cache and shard aggressively |
| Feed fetches per DAU | Many sessions; clients reuse data | Not every scroll is a full server reload—but still huge read QPS |
| Uploads / day | Tens of millions | Video drives storage, transcode CPU, and CDN egress |
| Read vs write QPS | Far more feed reads than new posts | Optimize read path; async everything on write |
| Egress | Often the main cost alongside compute | Say data out, not only request counts |
| Fan-out for 30M followers | 30M mailbox writes per post if naive | Must be policy-exempt or partial—queue speed alone does not save you |
Worked skew sketch: If one creator posts one Reel and you fan out to thirty million followers, you create on the order of thirty million mailbox inserts for a single tap—before transcode jobs or push notifications. That is why "always fan out" fails, even with a fast queue.
Implications:
- Any design where work per post grows with follower count without a cap breaks for celebrities.
- Transcoding and fan-out should run asynchronously with backpressure when queues grow.
- The feed request should limit how many candidates enter ranking so tail latency (for example p95) stays under control.
- Egress and encoding are first-class costs—not footnotes after QPS.
If you remember one thing: Numbers exist to show skew and bytes—reads dominate, celebrities break naive fan-out, video dominates bandwidth.
High-level architecture
What breaks if you merge everything
One service that stores full post JSON (including video bytes) in every follower mailbox, blocks post success on every transcode ladder, ranks with no timeout, and streams pixels through the feed tier will choke on celebrity traffic, melt the edge when ML slows down, and turn CDN egress into an API bandwidth bill.
What works: thin orchestration, heavy bytes elsewhere
From the phone's perspective, scrolling home means: "give me the next batch of posts after where I left off." The app receives JSON—captions, author fields, and URLs for thumbnails and video—not multi-megabyte files inlined in the response. The device fetches media separately from CDN caches close to the user.
Who owns what:
- API / edge — Auth, rate limits, timeouts to downstreams; upload session initiation.
- Feed service — Orchestrates the read path: candidates, graph checks, hydrate, CDN URL assembly, rank, cursor. Cap work here.
- Mailbox / timeline store — Ordered post IDs per viewer, sharded by
viewer_id. - Post service — Source of truth for captions, author id, timestamps, privacy, media keys,
media_processingstate. - Media pipeline — Transcoders, thumbnails, ABR ladders; triggered by queues after upload.
- Object storage + CDN — Blobs and segments; regional edge caching; signed or stable paths.
- Graph service — Follows, blocks, mutes—cached on the feed path; blocks filtered on read.
- Fan-out workers — Consume a queue; append to mailboxes where push policy allows; idempotent
(viewer_id, post_id). - Ranker — Scores a bounded candidate set under a hard time budget.
Celebrity / hybrid on the whiteboard: For authors you do not fully fan out, the feed service merges recent posts by author into the candidate pool. Draw that edge—or you only drew push fan-out and invite the follow-up you deserve.
[ Mobile client ]
→ [ Edge / API ] → [ Feed svc ] → [ Candidate store: mailboxes + optional merge ]
│ │ │
│ │ └──→ [ Ranker ] (timeout + fallback)
│ │
│ ├──→ [ Graph svc ] (follows, blocks)
│ │
│ └──→ [ Post svc ] → metadata only
│ │
│ ├──→ [ Media jobs ] → transcode / thumbs / ABR
│ │
│ └──→ [ Object store ] → [ CDN ] → (video/image bytes)
│
└── upload: [ Upload API ] → object store → enqueue transcode → post row durable
fan-out: [ Queue ] → workers → viewer mailboxes (idempotent)
In the interview: Narrate the read path first (latency budget, max candidates, ranker timeout, CDN URL shape). Then one write (durable post → async transcode → async fan-out). Storage brand names come after the story makes sense.
Async half (say it): Transcoding, fan-out, notifications, and search indexing are too slow for the post HTTP handler. Use queues or event streams (PostCreated, TranscodeComplete, FanOutRequested) with at-least-once delivery and idempotent workers. Hand off reliably via transactional outbox or CDC—not "commit then best-effort send" without a lost-message plan.
If you remember one thing: Hot path is IDs → metadata → policy → CDN URLs; pixels never stream through the feed tier.
Core design approaches
Most of the interview is not picking a brand of database—it is walking forks where each choice trades latency, cost, complexity, and failure behavior.
Upload and media processing
Clients upload chunks to object storage; the API creates a durable post row with media_processing: pending. Transcoders build ABR ladders, thumbnails, and poster frames; the row moves to ready or partial as artifacts land.
| Decision | If you optimize for… | You usually accept… |
|---|---|---|
| Resumable / chunked upload | Flaky mobile networks and large videos | More moving parts (session IDs, part completion, abandoned upload cleanup) |
| HTTP success when metadata + blob durable | Fast "posted" feeling | Processing states in the API—clients render pending / partial honestly |
| …every ladder exists before ack | Simpler "ready" mental model | Terrible tail latency and fragile post ACK at scale |
| Many ladder rungs + renditions | Playback quality and smooth ABR | Storage, transcode CPU, cache cardinality (more URLs to purge) |
| Fan-out in the upload request | Immediate visibility | Spiky load—most designs enqueue fan-out after the row is durable |
Interview line: Separate "can we show something?" (poster frame, low rung) from "is the full product-quality ladder done?"
Feed assembly (push / pull / hybrid)
| Policy | When it fits | Cost you accept |
|---|---|---|
| Push to follower mailboxes | Long-tail authors (modest follower counts) | Storage and fan-out CPU on publish |
| Merge / pull recent by author | Celebrities and mega-creators | Extra work on the home read path |
| Partial fan-out to active users | Middle tier or "online now" optimization | Stale mailboxes for inactive viewers |
Push for the long tail. For mega-followed authors, do not materialize every edge. The exact threshold matters less than saying there is a policy and naming the cost driver (queue depth, storage, blast radius).
Stories
Stories share DNA with feed posts (same graph, often same media pipeline) but differ in product rules—most notably short lifetime.
| Topic | Typical choice | Tradeoff |
|---|---|---|
| Lifetime | Fixed TTL (e.g. 24h) | Sweepers vs lazy delete; server-authoritative expiry |
| Storage model | Separate Story rows vs same table with type=story | Separate keeps TTL jobs simpler |
| Seen / replay state | High write volume if you persist every view | Sampling, batching, or eventual sync |
Interview line: Stories are time-bounded inventory with expiry semantics—not "feed with a flag."
Ranking
Treat ranking as a contract: bounded candidate IDs in, ordered list out, under latency and safety constraints.
Structural tradeoff: Generating candidates is cheaper than scoring the world. If you conflate them, every feed fetch runs the full recommender—p95 dies. Cap candidates, then rank. Say what happens at the ranker budget: timeout, recency fallback, cached last-good order.
If you remember one thing: Hybrid fan-out plus async media are the Instagram-shaped answers—pure push or sync transcode alone fails.
Data model
At scale there is no single database that wins every access pattern. Name source of truth vs cache vs derived for each arrow.
What lives where
| Kind of data | Typical home | Why |
|---|---|---|
| Post & user records | Relational DB or document store | ACID-ish create/update; indexes on author_id, created_at |
| Per-viewer feed candidates | Wide-column, key-value, or tiered mailbox store—sharded by viewer_id | Huge cardinality; append on fan-out; range scan for next page |
| Social graph | Edges table + heavy cache | Follows drive fan-out; blocks must be correct—read-time checks |
| Media blobs | Object storage + CDN | Bytes do not belong in OLTP rows |
| Hot read path | Redis cache, CDN for URLs | Sub-ms repeated metadata; no durability requirement for cache |
| Async work | Queues / Kafka | Transcode, fan-out, notifications—backpressure and replay |
Example schemas (illustrative)
Posts — source of truth for metadata and pointers:
post_id(PK),author_id,caption,visibility,created_atmedia_processing(pending|partial|ready|failed)media_manifest— original key, ladder entries per variant, poster key, thumbnail key
Mailbox / timeline (per viewer)—store IDs, not full posts:
- Key:
viewer_id+ shard; ordered list:post_id, optional score orinserted_at - Idempotency on
(viewer_id, post_id)for fan-out retries
Graph edges:
follower_id,followee_id,created_atblocker_id,blocked_id,created_at
Stories (often separate table):
- Media pointers plus
expires_at,story_kind; seen state optional or batched
Object storage layout
- Prefix by
post_idorauthor_id/post_idfor lifecycle deletes. - Originals vs derived artifacts in separate keys so transcode can retry per artifact.
- CDN URLs signed or stable; purge on bad encode or takedown.
Redis and caches (trimmed)
Redis is fast RAM with TTL—not durable post storage unless you are explicit about sync.
Strong fits: cache-aside for hot post metadata and profiles; rate limiting; small bounded per-user tail caches for merge; coordination keys for fan-out idempotency.
Risky fits: entire mailbox for every user in Redis only—memory explodes; recovery after failover is hard. Production systems often use wide-column mailboxes with Redis as a cache layer on top.
Interview land: Postgres (or similar) holds authoritative posts; mailbox storage holds IDs at scale; object storage holds media; Redis caches hot reads and powers rate limits.
Detailed design
Walk one post from “user tapped Share” to “friends can scroll it,” then one home-feed page load. Media makes Instagram different from a text-heavy social feed: the path that stores captions and pointers must stay fast, while video encoding and CDN delivery move on their own clock.
Write path (post + media)
On a phone with spotty LTE, uploading a long Reel as one unbroken HTTP request often fails mid-way. So the client usually requests upload URLs (or chunked upload sessions), pushes the original file into object storage, and only then asks the Post API to create the story metadata. That Post API call records who posted, the caption, visibility, timestamps, and the object keys—plus a processing flag such as media_processing: pending.
Success on that API means “we safely stored what we need to remember this post,” not “every quality level of the video already exists.” Returning only after ffmpeg finishes every bitrate would make post time track the worst encoding queue in the building. Instead, workers transcode thumbnails, poster frames, and adaptive bitrate ladders in the background, and they update the media manifest as each artifact lands. The phone can show a poster frame and start playback on a lower rung while higher rungs are still cooking.
When product rules say the post may appear in followers’ timelines, fan-out workers append the post id into follower mailboxes (idempotently, so retries do not duplicate). For mega-creators you skip full fan-out and rely on merge-on-read—same hybrid idea as Facebook Feed, with even more pressure because each item also references large media. Search index updates, notifications, and Story-specific fan-out should trail this path via an outbox or event stream so a slow notifier cannot block “posted.”
Read path (home feed)
When someone opens Home, the feed service first knows who is scrolling and which product mode they are in (following vs “for you,” if that is in scope). It loads a bounded set of candidate post ids from that viewer’s mailbox, plus any celebrity merge. Bounding matters: ranking cannot score “everything everyone I follow ever posted” on every swipe.
Next it batch-loads post metadata and author cards, then filters blocks and hard policy at read time so a blocked account does not slip through a stale mailbox entry. For each surviving post it chooses which media URLs to return—thumbnail, poster, HLS manifest—based on the client’s capability and the current media_processing state. Ranking runs only on that capped list, with a hard time budget; if the model is slow, fall back to recency or a cached order rather than spinning an empty feed. The response stays a small JSON page of ids, captions, and CDN pointers; the client fetches video bytes from the CDN separately. An opaque cursor lets the next swipe continue without offset pagination lies when order moves.
In the room (spoken): “Upload to object storage, durable post row with processing pending, ack before full ladders exist. Async transcode and hybrid fan-out. On read, cap candidates, hydrate metadata, map to CDN variants, rank under a timeout, return a cursor—never put video bytes in the feed JSON.”
Architectural dig: one Reel post (ack vs ladder) and one celebrity publish
High-level boxes showed ownership. This dig is how posting stays fast when ffmpeg is slow, and how scroll stays cheap when a creator has thirty million followers.
1) Post ack: metadata durable, ladders async
Responsibility: Post service owns durability and media_processing state. Media workers own transcode artifacts. Feed service must not wait on every ladder before the client gets success.
- Client finishes chunked upload to object storage.
- Post API persists row with media keys and
media_processing: pending. - Return 201 with
post_idand processing state; client shows poster frame or optimistic UI. - Enqueue transcode jobs; workers emit
TranscodeCompleteper variant; row moves topartialthenready. - Fan-out enqueues when visibility rules say so—often after basic thumb/poster exists, not after every rung.
2) Ack vs full transcode ladder (bad vs great)
Bad design: block HTTP on every encoding rung
User on 3G posts a 60s Reel. API waits for ffmpeg to finish all bitrates before returning. Post latency spikes to minutes; gateways time out; retries duplicate work; users think the app is broken even when upload succeeded.
Upload done ──► API waits for full ladder ──► timeout / retry storm
│
└── user sees spinner; fan-out never starts
Great design: ack on durable metadata + blob; ladders land async
Upload and post row commit; API returns immediately with media_processing: pending. Client plays lowest available rung via ABR while higher bitrates land. Feed returns the post with processing state—never an empty timeline.

Figure: Success on post is not success on every bitrate. The API contract must expose processing state; the client and CDN handle progressive quality.
Interview land: "I never block post ack on ffmpeg. I do block fan-out on nothing—metadata must be durable first."
3) Celebrity blast radius (bad vs great)
Bad design: always push to every follower
A creator with thirty million followers hits Post. Workers attempt thirty million mailbox writes. Fan-out queue ages; friends' feeds look stale for minutes while create-post dashboards stay green.
Post 201 ──► enqueue fan-out ──► 30M mailbox writes
│
└── queue age ↑ while API success looks fine
Great design: hybrid policy by follower tier
Classify the author. Long-tail: push to mailboxes. Mega-followed: store in an author-indexed recent list and merge on read into each viewer's candidate set (optionally push only to recently active viewers).
Long-tail author → push post_id to follower mailboxes
Mega-creator → append to author tail; feed read merges into candidates
Scale inside the box: Monitor queue age, writes per shard, and time-to-first-visibility—not only create 201 rate.
Failure inside the box: If workers die mid-fan-out, idempotent retries finish the long tail; celebrity merge still lets actives see content from the author store.
4) Read: bounded candidates under a rank budget
- Authn viewer; load block/mute set (strict freshness for blocks).
- Read mailbox head + merge celebrity tails → cap candidates (hundreds, not unbounded).
- Batch-get posts + authors; drop tombstones and blocked authors.
- Map media keys to CDN URLs per variant; include
media_processingin each item. - Call ranker with deadline T ms; on timeout use recency or last known order.
- Return page of size K + opaque
next_cursor.
5) Numbered happy path (put it together)
- Upload → durable blob + post row → 201 with
pendingprocessing. - Transcode jobs land variants async; fan-out (or celebrity skip) → mailbox IDs where policy allows.
- Home GET → candidates → hydrate → CDN URLs → filter → rank or fallback → cursor.
- Client fetches bytes from CDN; ABR upgrades as ladders complete.
If you remember one thing: Post ack, media ready, and timeline visible are three different SLOs.
Key challenges
| Challenge | What users see if it goes wrong | What to say in the interview |
|---|---|---|
| Transcode lag | "Posted" but Reel spins on processing for hours | Ack on metadata; media_processing states; priority lanes for transcode |
| Celebrity fan-out | Friends' feeds stuck while posting still "works" | Hybrid policy; queue age alerts; merge on read |
| CDN / egress hot key | One viral Reel stutters globally | Variants per resolution; origin shield; singleflight; watch egress per key |
| Moving ranks | Duplicate posts or gaps while scrolling | Opaque cursors; admit best-effort dup/skip |
| Stories expiry | Ghost stories or missing new ones | Server-authoritative TTL; sweeper metrics; CDN manifest TTL |
| Like hot keys | Feed fine; like counts wrong or slow | Shard counters per post_id; cache reads; rate-limit writes |
If you remember one thing: Video + skew dominate cost—fan-out, transcode, and egress are not afterthoughts.
Scaling the system
Shard mailboxes by viewer_id. Shard post metadata by post_id or author-time. CDN is how you scale bytes—not bigger feed JSON.
For hot posts, use request coalescing (singleflight) and TTL jitter on metadata caches—thundering herd on a viral Reel ID is a classic failure mode.
Multi-region: Graph and media replication lag is real; eventual visibility across regions is more honest than strong global consistency for every mailbox row.
Cap pull-merge fan-in when someone follows thousands of accounts—otherwise hybrid still burns CPU on read.
If you remember one thing: CDN scales bytes; mailboxes scale read QPS; transcode fleet scales encode backlog.
Failure handling
| Scenario | What the user sees | What to build |
|---|---|---|
| Ranker slow or down | Spinners or empty home | Hard timeout; recency fallback; circuit breaker; feature-flag heavy models |
| Transcode backlog | Post succeeded; Reel stays on processing | Serve poster / low rung; alert on oldest job age; priority lanes |
| CDN / origin hot spot | One viral Reel stutters; origin errors | Origin shield; singleflight; regional failover; monitor origin per key |
| Fan-out backlog | Post succeeded; friends see stale home | Alert on queue age; merge-on-read; reads succeed from stale mailboxes + merge |
| Graph service degraded | Blocked user appears briefly | Circuit break; filter blocks at read; fail closed where abuse risk is high |
If you remember one thing: Never return an empty feed when transcode lags—return posts with processing media states.
API design
Illustrative REST surface (GraphQL is fine if you discuss batching and N+1—feeds amplify bad graphs).
POST /v1/media/uploads # or /uploads:init + chunked parts
POST /v1/posts
GET /v1/feed
GET /v1/posts/{post_id}
GET /v1/stories/reel
POST /v1/users/{user_id}/follow
DELETE /v1/users/{user_id}/follow
POST /v1/posts/{post_id}/like
GET /v1/posts/{post_id}/comments
Home feed — GET /v1/feed
| Query param | Role |
|---|---|
cursor | Opaque continuation; may embed ranker state |
limit | Page size (cap server-side, e.g. ≤ 20–50) |
mode | e.g. following vs for_you if product has both |
session_id | Experiments / snapshot behavior (optional) |
Response sketch: { "items": [ Post ], "next_cursor": "...", "has_more": true }. Each Post includes media with status (ready/processing/partial), urls or playback descriptors per variant, counts, author summary.
Errors: 401 / 429 with Retry-After; avoid leaking blocked user existence if policy requires.
Upload — POST /v1/media/uploads
- Return upload session id and part URLs or signed PUT targets.
Idempotency-KeyonPOST /v1/postsso flaky networks do not duplicate posts.
Stories — read
Separate resource with TTL hints in response; server is source of truth for ordering, privacy, and expiry.
Cross-cutting
- Rate limits on upload and create to fight abuse.
- Version mobile clients; backward-compatible field adds for
media_processingstates.
In the interview: One minute on idempotent post create, cursor semantics, media_processing in responses, and why likes do not own feed p95.
Observability (what you measure)
| Signal | Why it matters |
|---|---|
| Post create success vs transcode oldest job age | Explains "posted but Reel still processing" |
| Post create vs fan-out queue age | Explains "posted but friends do not see it" |
| Time-to-first-visibility (sampled) | Product freshness SLO |
| Ranker p99 + timeout / fallback rate | Separates rank health from feed availability |
| Candidates scored per request | Catches unbounded merge |
| CDN origin QPS / egress per hot object key | Viral Reel stampede and cost |
media_processing pending rate in feed responses | Honest degradation visibility |
| Empty feed / 5xx rate | User-visible outages |
Green create rates alone will lie while timelines feel stale or Reels spin on processing.
Security and abuse
Authenticate every feed and create call. Authorize visibility (public, followers-only, blocked) on read, not only at fan-out time. Rate-limit upload, post create, follow, and like to slow spam and bot farms. Signed upload URLs with short TTL and content-type constraints reduce arbitrary blob abuse. Treat ranking and moderation logs carefully—do not dump private captions into unrestricted analytics. Report flows and integrity pipelines (fake engagement, coordinated amplification) belong beside the feed, not as synchronous mailbox rewrites.
Cost awareness
Every pushed mailbox row costs storage and write IOPS until trimmed. Celebrity push-to-all is a cloud bill incident. Transcode CPU and CDN egress often dominate Instagram-shaped systems—video bytes are not free like text metadata. Many ABR ladder rungs improve playback but multiply storage, encode cost, and cache cardinality. Caching post metadata reduces post-store load but needs stampede controls on viral IDs. Choose explicitly whether you spend money on precompute storage, read-time merge CPU, or encode/egress quality.
Production scenes
Textbooks teach boxes and arrows. On-call teaches this: post create can look healthy while Reels spin on processing and feeds feel stuck in yesterday.
Scene 1: Transcode backlog while posts "succeed"
The moment: User taps Share on a Reel. App shows "posted." Playback stays on a poster frame or low quality for hours after an incident.
The trap: Transcode capacity is finite. Metadata and fan-out can run while ladders lag. Dashboards that only chart create 201 hide oldest job age.
What to build: Alert oldest transcode job age; priority lanes for user-visible posts; serve low rungs first; honest media_processing in API; feature flag to relax non-critical encodes during incidents.
Scene 2: Fan-out backlog while posts "succeed"
The moment: A live event or creator posts. Create still works. Friends refresh and still see yesterday's top of feed.
The trap: Fan-out is async. Workers append at finite speed. Time-to-visible is a different SLO than post ack.
What to build: Alert on queue age and per-shard backlog. Hybrid merge on read while queue drains. Priority lanes for recent posts vs backlog drain.
Scene 3: Ranker deploy hangs the feed
The moment: After a ranking release, homes spin; unrelated routes feel slow.
The trap: Ranker sits on the hot path without isolation. Missing timeout fills the edge thread pool.
What to build: Hard rank timeout; circuit breaker; recency fallback; kill switch for heavy models. Separate SLOs: feed loads vs perfect rank.
Scene 4: CDN stampede on one viral Reel object
The moment: One viral Reel; feed still loads but p99 spikes; origin errors while average cache hit ratio looks fine.
The trap: Every scroll multi-gets the same post_id and CDN object key. Aligned TTL expiry creates a miss herd; egress spikes.
What to build: Singleflight per key; origin shield; TTL jitter; stale-while-revalidate; watch origin QPS and egress on one key, not only cluster CPU.
In the interview: Pick one scene. Tell what users felt, which metric lied, and what you would ship next.
Bottlenecks and tradeoffs
Encoding cost vs playback quality
The tension — More ABR ladders and prefetch feel great on Wi‑Fi; each variant is storage + transcode CPU + CDN cache cardinality.
What breaks — Transcode queue backlog; users see processing forever during incidents.
What teams do — Priority lanes; serve low rungs first; shed non-critical encodes; honest media_processing states in API.
Say in the interview — Separate "can show something" from "full ladder done."
Push fan-out vs read merge
The tension — Push makes scroll cheap; celebrities make writes impossible.
What breaks — Queue depth and storage blast radius on one post.
What teams do — Hybrid policy by follower count; merge author tail on read; cap candidates.
Say in the interview — Name who you fan out to—not "Kafka."
Metadata path vs bytes path
The tension — Inlining media in feed JSON feels simple; it destroys latency and egress economics.
What breaks — API bandwidth bills; p95 blows up on large responses; CDN never gets a cache hit on personalized JSON.
What teams do — Feed returns URLs and processing state; client fetches variants from CDN; ABR handles partial ladders.
Say in the interview — IDs → URLs on the hot path; pixels on the CDN.
If you remember one thing: Instagram tradeoffs are bytes + skew—not only feed algorithm labels.
Interview tips
You have the full design in mind now. These six back-and-forths are how interviewers test whether you can defend it under pressure. Each one starts with a tempting shortcut, an interview push, and a clear answer.
Post ack vs video ready
You might say: "We wait until transcoding finishes before returning success."
Interview Push: "User on 3G posts a 60s Reel—what happens to post latency?"
Land here: Return success when metadata and blob upload are durable; expose media_processing: pending in the API; client shows poster frame and ABR while ladders land async. Blocking HTTP on ffmpeg is a scale mistake. Say what the feed returns while processing—never an empty timeline.
Fan-out to everyone
You might say: "Every post fans out to all followers immediately."
Interview Push: "Creator with 30M followers—how many mailbox writes?"
Land here: On the order of thirty million mailbox inserts for one click if naive. Use hybrid: push for long tail; merge on read or author-indexed tail for head; partial fan-out to active users only. Name queue depth and storage blast radius—not only "we use Kafka."
Feed as one join
You might say: "SELECT posts JOIN follows ORDER BY time."
Interview Push: "Someone follows 5,000 accounts—cost per swipe?"
Land here: Candidate IDs from mailboxes + optional merge; multi-get post rows; no giant join on hot path. Cap candidates before rank. Feed JSON carries pointers and CDN URLs—not video bytes.
CDN as a label
You might say: "We use a CDN."
Interview Push: "Viral Reel—what object key melts, and what do you purge?"
Land here: Variants per resolution/ladder; signed URLs; origin shield; hot key on one object id—monitor egress and origin CPU, not only API QPS. Purge or invalidate per variant on bad encode or takedown.
Ranking on the critical path
You might say: "Home For You runs the full model synchronously."
Interview Push: "Feature store slow—does scroll stop?"
Land here: Bounded candidates → rank with hard timeout → recency fallback. Separate candidate generation from scoring. Perfect rank that empties the feed is a product failure.
Stories bolted on
You might say: "Stories are just posts with a flag."
Interview Push: "What happens at 24 hours?"
Land here: TTL, sweepers, often separate storage/API; different ranking hooks; server-authoritative expiry—not only client hide. Align CDN manifest TTL with metadata expiry.
Red flags to avoid without correcting yourself: "Block post on transcode," "fan out to everyone," "full video in feed JSON," "rank with no timeout," "Stories are only a flag."
After each interview push, close with one real part of the design you would build—processing states, hybrid threshold, idempotent (viewer_id, post_id), ranker timeout, or CDN variant URLs—not "we'll scale it later."
What should stick
After reading this guide, you should be able to explain:
- Two clocks on post — App can say “posted” while video is still processing; friends’ feeds catch up on their own timeline.
- Two lanes — Light info (who posted, caption, post id) vs heavy bytes (video files on a CDN).
- Copy a pointer, not the video — Put a post id into followers’ lists where cheap; for mega-creators, merge on scroll instead of writing tens of millions of copies.
- Home stays bounded — Cap how many candidates enter ranking so one slow ranker does not blank the feed.
- Degrade honestly — Processing states and recency beats empty cards when transcode or ranking lags.
Tell it in the room: “Upload lands durable bytes and a post row first—HTTP success does not wait for every video quality. Fan-out copies post ids for normal authors; mega-creators merge on read. Scroll loads capped ids, fetches metadata, maps to CDN URLs, ranks under a timeout. When processing lags, show a processing state—not a blank card.”
Related Topics
- Facebook Feed System Design — Text-heavy feed contrast: same hybrid fan-out and ranking bones without the media pipeline depth
- WhatsApp System Design — Messaging contrast: per-thread order vs feed fan-out and CDN-backed media pointers
- Distributed Cache System Design — Hot post metadata, stampede, and TTL jitter on viral IDs
- CDN System Design — Edge caching, origin shield, and egress when every Reel references CDN URLs
- Rate Limiter System Design — Protecting upload, create, and follow from abuse
Frequently asked follow-ups
- How does photo or Reel upload work end to end?
- What is the difference between following feed and Explore?
- How do you handle a creator with tens of millions of followers?
- Where do Stories live and how do they expire?
- How do likes scale on a viral post?
Deep-dive questions and strong answer outlines
Walk through posting one photo or Reel.
Client uploads chunks to object storage via presigned URLs or an upload session. Post API creates a durable row with media keys and media_processing: pending. Return success when metadata and blob are durable—not when every transcode ladder exists. Enqueue transcode and thumbnail jobs asynchronously. When product rules allow visibility, fan-out workers append post IDs to follower mailboxes with idempotent (viewer_id, post_id) keys. Celebrity authors follow hybrid policy: skip full fan-out, merge on read. Side effects (search, notifications) trail the critical path.
Walk through reading one page of the home feed.
Load a bounded set of candidate post IDs from the viewer mailbox plus any celebrity merge. Batch-get post metadata and authors. Filter blocks and policy. Map media keys to CDN URLs per client capability (thumb, poster, HLS manifest). Rank under a hard timeout with recency fallback. Return items plus opaque next_cursor. Feed JSON carries pointers and URLs—not multi-megabyte video inlined in the response.
How is Explore different from the following feed?
Following feed is driven by the social graph and hybrid fan-out or merge. Explore is a retrieval and rerank problem over a much larger candidate pool—often offline-generated candidates plus online rerank—not the same mailbox fan-out path. Unless the interviewer expands scope, treat Explore as out of scope or a separate recommendation surface.
How do Stories work at scale?
Short TTL (for example 24 hours), often separate storage or table from main feed posts. Fan-out to followers only; server-authoritative expiry with sweepers; CDN manifest TTL aligned with metadata TTL. Seen state may be sampled or batched to avoid write storms.
What happens when a Reel gets millions of likes?
Shard counters per post_id; rate-limit write amplification; cache read counts with eventual consistency. Hot keys on one post_id need coalescing and monitoring—likes must not own feed p95.
AI feedback on your design
After a practice session, InterviewCrafted summarizes strengths, gaps, and interviewer-style expectations—similar to a written debrief. See a static example report, then practice this problem to get feedback on your own answer.
FAQs
Q: Do I need to design GPU filters in the interview?
A: Usually no. Filters are client-side or async offline jobs—off the post ack critical path. Mention them in one sentence if asked, then return to upload durability, transcode queues, and feed read budgets.
Q: Are direct messages in scope?
A: DMs are a separate real-time messaging stack (closer to chat than feed). Unless the interviewer widens scope, park DMs and focus on home feed, upload, and optional Stories.
Q: How do Reels differ from photos on the delivery path?
A: Reels need adaptive bitrate (ABR) ladders, segment manifests, and more CDN egress. The feed still returns URLs and processing state—the phone fetches bytes from the CDN. Blocking post success on every ladder rung is a scale mistake.
Q: How is Instagram feed different from Facebook feed?
A: Both share hybrid fan-out, mailboxes of IDs, and ranking timeouts. Instagram adds a media-heavy layer: resumable upload, async transcode, variant URLs, and egress as a first-class cost. A Facebook-style answer that only discusses text posts and fan-out misses half the interview.
Q: Is Explore required in every Instagram interview?
A: No unless you agree scope in clarifying questions. Home and Stories are the common core. Explore is a separate candidate-generation and rerank problem—name it as out of scope unless they push.
Q: What should I alert on in production?
A: Transcode oldest job age, fan-out queue depth, time from post create to first mailbox visibility, ranker p99 and timeout rate, CDN origin QPS per hot object key, and feed empty-error rate—not only post create 201s.
Practice interactively
Open the practice session to use the canvas and stages, then review AI feedback.