Instagram Interview Questions | JiQuest

add

#

Instagram

System design deep dive · HLD

Design Instagram: full high-level design.

Requirements, back-of-envelope capacity estimation, a high-level design diagram, a deeper deployment architecture diagram, sequence diagrams for uploading a post and generating a feed, and an entity-relationship diagram - with the async media-processing pipeline and hybrid feed fan-out worked through in detail.

100MPosts uploaded / day
~50:1Feed reads : uploads
5 variantsImage sizes generated / upload
Phone camerauploads photo Object storageoriginal saved Processing queueresize + thumbnail CDN edgeserves variants Followers' feedsnotified when ready thumbnail, feed, story, DM sizes

1. Clarify requirements before drawing any box

Instagram is really two systems glued together: a media-processing pipeline that turns one uploaded photo into many delivery-ready variants, and a feed system that decides, for every user, which of those variants to show and in what order.

Functional requirements

Upload a postPhoto or short video, optional caption, optional multi-image carousel.
Home feedReverse-chronological or ranked feed of posts from accounts the user follows.
Likes and commentsLightweight engagement actions with visible counters.
Follow / unfollowAsymmetric relationship; public accounts are followable without approval.

Non-functional requirements

Fast perceived uploadThe app must show "posted" almost immediately even though processing takes seconds.
Low feed-scroll latencyInfinite-scroll feed pagination must feel instant; target <200ms p99 per page.
High durability for mediaOriginal photos/videos must never be lost, even if a processing worker crashes mid-job.
Read-heavy scaleFeed reads and story views vastly outnumber uploads.
Explicitly out of scope Stories/reels-specific ephemeral storage, DM/chat, and ML-based ranking model internals are noted as extensions on top of this core feed-and-media design rather than part of the core.

2. Back-of-the-envelope capacity estimation

The numbers that matter most here are storage per post (multiple image variants) and the multiplier between one upload and how many feed reads it eventually serves.

MetricAssumptionResulting estimate
Posts uploaded (writes)100M posts/day, mostly photos, ~10% video~1,150 writes/sec average, ~6,000/sec peak
Feed reads500M DAU × ~10 feed page loads/day~58,000 reads/sec average, ~200,000/sec peak
Storage per photo postOriginal ~4MB + 5 derived variants (~1.5MB total)100M/day × 5.5MB ≈ 550 TB/day of new media (before compression/tiering)
Processing throughput90M photos/day need resize + thumbnail + filters~1,050 jobs/sec average on the processing queue, needs autoscaled worker fleet
Feed cache footprintCache last ~500 post IDs per active user, ~80 bytes/entry500M users × 500 × 80B ≈ 20 TB across the Redis fleet
Why this matters The gap between upload volume and storage volume (one post becomes five-plus stored variants) is why media is never processed synchronously on the request path - it justifies the entire async pipeline and the CDN-first delivery strategy described below.

3. High-level design (HLD)

The HLD separates "accept the upload and acknowledge fast" from "do the expensive work," and separates the write path (post) from the read path (feed) the same way a URL shortener separates create from redirect.

Clientmobile app API gatewayL7, auth Post servicewrite path Feed serviceread path Object storageoriginals (S3) Processing queueresize / transcode Feed cacheRedis, per-user list CDNderived variants Fan-out workersnotify followers Follow graph
Stateless servicesFast-path infraDurable storageAsync / workers

What each box owns

Post service (write path)

Issues a pre-signed upload URL so the client uploads the original directly to object storage (never proxied through the app tier), writes a post row in "processing" state, and enqueues a processing job. It returns to the client as soon as the row exists, well before any resized variant is ready.

Processing queue and workers

Pull jobs, download the original, and produce a fixed set of derived variants (thumbnail, feed-resolution, full-screen, story crop) plus a video transcode if applicable. Each variant is uploaded to object storage and pushed to the CDN origin; when all variants exist the post flips to "ready" and fan-out is triggered.

Feed service (read path)

Reads the requester's pre-computed feed cache (post IDs pushed there when followed accounts posted), hydrates post metadata and CDN URLs, and paginates. Like the timeline problem in other social feeds, very large accounts are excluded from push fan-out and merged in at read time instead.

Object storage, CDN, and follow graph

Object storage is the durable source of truth for both originals and derived variants; the CDN caches derived variants at the edge since they are immutable once generated - a post's image never changes without becoming a new object. The follow graph is a dedicated adjacency-list service shared by both the fan-out workers and the feed service.

4. Detailed architecture diagram

The architecture diagram makes the processing pipeline concrete - specific worker pools per media type - and shows how feed fan-out reuses the same push/pull split other feed-shaped systems need.

Edge layer CDN (derived variants) API gateway + L7 LB Direct-to-storage uploadspre-signed URL, bypasses app tier Rate limiter / abuse checks Media processing pipeline Image workers ×40 Video transcode workers ×20 Job queue (SQS/Kafka) Thumbnail / crop / filter GPU pool Feed path (push + pull merge) Feed svc ×24 pods Rank + hydrate + paginate Pull: high-follower accounts Read-through post-metadata cache Object storage tiers Hot (recent) Cold (archival) lifecycle policy moves old originals to cold tier Fan-out Fan-out workers ×30 (push to feed cache) skipped for accounts > 1M followers Engagement pipeline Like/comment counters (Kafka) batched async increments
DecisionChoiceReasoning
Upload pathDirect-to-storage via pre-signed URLRemoves large binary payloads from the app tier entirely; app servers only ever handle small JSON requests.
Processing modelAsync queue + autoscaled worker poolResize/transcode time (seconds) must never block the client's perceived "post uploaded" moment.
Feed fan-outHybrid: push for normal accounts, pull for >1M followersSame amplification problem as any social feed - bounds worst-case fan-out cost per post.
Storage tieringHot tier recent, cold/archival for old originalsOriginals are rarely re-processed after initial upload; keeping them all on hot storage indefinitely is unnecessary cost.

5. Sequence diagrams for the two critical flows

These flows show exactly where "upload finishes" and "post is visible in feeds" diverge in time - a distinction that's easy to gloss over in prose but has to be explicit in a sequence diagram.

5.1 Upload and process a photo post

Client Post svc Object storage Processing queue Workers 1. POST /posts (metadata) 2. pre-signed upload URL 3. PUT original.jpg 4. enqueue processing job 5. 201 Created {status:processing} 6. worker: resize, thumbnail, upload variants 7. mark post ready, trigger fan-out

Step 3 uploads directly from client to storage, never through the Post service - the service only ever handles the small metadata request. Step 5 returns "processing," not "posted" - real apps show the post optimistically in the author's own profile immediately, while step 6/7 (seconds later, fully async) is what actually makes it appear in followers' feeds.

5.2 Load a home feed page

Client Feed svc Feed cache Post metadata CDN 1. GET /feed?cursor= 2. LRANGE cached post_ids 3. ids page 4. fetch post metadata + CDN URLs 5. rows 6. 200 OK {posts page} 7. client fetches images directly

Step 4/5 fetch metadata (caption, like count, CDN URL) but never the image bytes themselves - the Feed service response is a small JSON payload. Step 7 shows the client fetching the actual image directly from the CDN in parallel, which is what keeps a feed page load fast regardless of how many photos are on it.

6. Entity-relationship (ER) diagram and schema

The data model separates the mutable social graph and engagement data from the largely immutable post record, and never stores media bytes in the relational layer at all - only CDN-addressable references.

users PK id BIGINT username VARCHAR is_private BOOLEAN follower_count BIGINT created_at TIMESTAMP posts PK id BIGINT FK author_id BIGINT media_type ENUM(photo,video) cdn_base_url VARCHAR caption VARCHAR status ENUM(processing,ready) created_at TIMESTAMP follows FK follower_id BIGINT FK followee_id BIGINT created_at TIMESTAMP likes FK post_id BIGINT FK user_id BIGINT created_at TIMESTAMP PK(post_id, user_id) 1N 1..N NN likes is a many-to-many join between users and posts

Key modeling decisions

posts never stores media bytescdn_base_url is a prefix the client appends a variant suffix to (e.g. /thumb.jpg, /feed.jpg); media itself lives only in object storage + CDN.
status field gates visibilityA post only appears in any feed once status flips to ready, so a half-processed post can never be fanned out prematurely.
likes uses a composite primary key(post_id, user_id) both enforces "one like per user per post" and gives an index for "did I like this" checks.
like_count is denormalized onto postsFeed rendering needs it instantly; it's updated by an async aggregator, not incremented synchronously per like.
Storage choiceUse whenWatch out for
Relational (sharded by author_id) for postsYou want straightforward "all posts by this author" queries for profile pages.Cross-shard queries for a mixed feed require the feed cache to already hold the fan-out, not a live join.
Wide-column / key-value for likesLike volume is extremely high and access is always by post_id or (post_id,user_id).Aggregate "who liked this" listings at very high like counts need pagination, not a full scan.

7. Deep dives interviewers actually probe

Why process media asynchronously instead of resizing on upload?

Resizing to five-plus variants and transcoding video can take several seconds, and doing it synchronously would tie up an app-tier request thread per upload and make the client wait through the slowest step (video transcode) before it even gets an acknowledgment. Making it async means the client gets a fast "accepted" response, the app tier stays lightweight, and the worker fleet can be scaled and retried independently of request traffic.

How is feed fan-out kept from being overwhelmed by an account with 50M followers?

Same problem as any social feed: push fan-out is used for typical accounts, but accounts above a follower-count threshold are excluded from push entirely and instead pulled at read time by the Feed service, merged with the pushed portion of the feed, and re-sorted. This bounds worst-case fan-out cost per post regardless of the author's audience size.

How do you avoid re-encoding the same video at multiple resolutions from scratch for every request?

Encoding happens exactly once, at upload time, producing a fixed bitrate ladder (e.g. 480p/720p/1080p) that is stored and cached at the CDN; playback never triggers a new encode. This trades upfront processing cost (paid once per upload) for near-zero marginal cost per view, which is the right trade-off given views vastly outnumber uploads.

What happens if a processing worker crashes mid-job?

The original was already durably written to object storage before the job was enqueued, so nothing is lost - the queue's visibility-timeout/retry mechanism redelivers the job to another worker after a timeout. Workers are also idempotent: re-running the resize step simply overwrites the same derived-variant object keys, so a retried job produces the same result rather than duplicate posts.

What's the single biggest bottleneck as this scales 10x?

Not the feed read path - caching and CDN delivery scale horizontally. The real pressure point is the media processing pipeline during traffic spikes (e.g. a major event driving a burst of video uploads), since video transcoding is CPU/GPU-bound and far more expensive per job than image resizing. The mitigation is prioritizing image jobs ahead of video jobs in the queue and autoscaling the GPU transcode pool independently, so a video backlog never delays photo posts from appearing in feeds.

8. Summary: what a strong answer covers

Clarified scope before designingJustified every number with a calculationMade media processing fully async Uploaded directly to storage, not through the app tierReused the push/pull hybrid for feed fan-outKept media bytes out of the relational layer entirely
Interview tip The strongest signal in an Instagram design interview is drawing a clear line between "upload acknowledged" and "post visible in feeds," and explaining exactly what makes that gap safe (durable original write before the async job, idempotent workers, a status flag that gates visibility).
No comments
Leave a Comment