Design Instagram
Photo posts, follows, a home feed and explore, with uploads that never block the app.
- Object and blob storage — Immutable files by name, replicated and cheap.
- CDNs and edge caching — Copies of static bytes near the user, and how they stay fresh.
- Fan-out on write versus fan-out on read — Pushing a post to every follower's inbox, or assembling the feed when asked.
- Caching strategies — Read-through, write-through, write-back, TTLs and invalidation.
- Sharding and partitioning — Splitting data by key so each machine holds a slice it can handle.
01The design, in the six-step framework
1. Requirements
Functional
- Post photos and short videos with captions; follow people; a home feed of posts from followed accounts; an explore tab of recommended posts.
- Likes and comments; a profile grid of a user's own posts.
- Out of scope: stories (see stories), direct messages, the recommendation model's internals.
Non-functional
- 1 billion monthly users, 500 million daily; 100 million posts a day; average 2 MB per photo, 20 MB per video.
- Upload returns in under 2 s on a mobile network; the feed loads in under 200 ms; images appear in under 300 ms worldwide.
- Media is never lost; a post is visible to the author immediately and to followers within seconds.
- Read-heavy: 5 billion feed loads a day; each shows 20 posts.
Media ingest: 108 posts/day × 3 MB average ≈ 300 TB/day ≈ 3.5 GB/s; over a year 110 PB of originals plus renditions.
Image serving: 5 × 109 feed loads × 20 posts × 200 KB rendition = 2 × 1016 B/day ≈ 230 GB/s, almost all from the CDN; origin sees a few percent.
Post metadata: 108 × 365 × 500 bytes ≈ 18 TB/year, sharded.
2. Core entities
- User: id, handle, profile, counts.
- Post: id (time-ordered), author, caption, media ids, created-at, like and comment counts.
- Media: id, type, original blob, renditions (sizes and formats), processing status.
- Follow: follower, followee.
- Feed inbox: user → recent post ids; Like: (user, post); Comment: post, author, text, time.
3. API
POST /media/uploads→ signed upload URL and media id; the client uploads bytes straight to storage;POST /media/{id}/completewhen done.POST /postsbody: caption, media ids → post id; the post is created with the client's locally generated thumbnail until renditions are ready.GET /feed?cursor=,GET /explore?cursor=→ pages of hydrated posts with rendition URLs chosen for the device.POST /posts/{id}/likes,POST /posts/{id}/comments,GET /users/{id}/posts?cursor=.
4. High-level design
A post from camera roll to a follower's feed:
- The app asks for an upload URL and streams the original directly to object storage, resumable in chunks; the API never carries the bytes.
POST /postscreates the post row immediately. The app already has a small preview, so the author sees the post at once.- Media processing produces renditions (several widths, modern formats, a video transcode) and marks the media ready; the post's rendition URLs change from "original" to the small files.
- Fan-out pushes the post id into followers' inboxes as in the news feed design; the feed read merges inbox, celebrity pulls and ranking, and hydrates from the post store. Images load from the CDN.
5. Deep dives
Uploads that never block the app
The 2 s target on a mobile network is impossible if the upload waits for processing, so the design makes the post visible before the media is ready. Three pieces: a direct-to-storage upload through a signed URL (no API server in the byte path, resumable by chunk), a post row that references media by id with a status, and a client-generated preview the author sees immediately. Followers who load the feed in the seconds before renditions exist get either the original (large, fine for a few) or are served the post only after processing, which is the usual product choice. Processing is an asynchronous pipeline consuming the media-created event; a video that fails to transcode leaves the post in a "processing" state the author can see, never a broken feed.
Serving 230 GB/s of images
Every rendition is immutable and named by media id, size and format, so the CDN caches it for a year and a popular post is served from edge memory. The client asks for the width it will draw and sends an Accept header, so a modern phone gets a 480-pixel AVIF of about 60 KB rather than a 2 MB original. Prefetch the next screen of thumbnails while the user scrolls. Origin capacity is for cache misses only, so a long-tail post viewed once still reads from object storage, and a regional object-storage replica keeps that miss within the continent. The number to say: at a 95 percent hit rate the origin serves about 12 GB/s, which a few hundred storage nodes handle.
The home feed versus explore: two different read paths
The home feed is the inbox-plus-celebrity-pull design with chronological or lightly ranked order; it is bounded by who you follow. Explore is unbounded: a ranking pipeline picks candidates from several sources (posts liked by accounts similar to you, trending in your region, topics you engage with), scores a few thousand with a model, and pages through them with a cursor over a precomputed per-user candidate list refreshed every few minutes by a background job. Keeping explore off the home-feed path matters: an explore outage should degrade one tab, not the app. Both tabs hydrate the same way, through batched reads and a post cache.
Likes and comments on a viral post
A viral post receives thousands of likes a second. Writing each like as a row is fine (sharded by post id, append-only), but incrementing a single counter row at that rate is a hot spot. Keep the like record for idempotency ("did I like this?") and compute the displayed count from a sharded counter aggregated every few seconds. Comments are a list per post with cursor pagination, newest or most relevant first, with a per-post cache of the first page; a comment on a viral post invalidates only that post's first-page cache entry. Moderation (a classifier on the comment text) runs in line for obvious abuse and asynchronously for the rest.
The profile grid and private accounts
A profile page lists one author's posts newest first, which is a range read on the post store if posts are sharded by author with a time-ordered id as the sort key; but the feed hydrates by post id, which prefers sharding by post id. The usual answer is both: the post store is keyed by post id, and a small secondary table per author holds (author, post id) in time order, written in the same transaction as the post. Private accounts change fan-out and serving: a post from a private account is pushed only to approved followers, the follow-request flow is a pending edge that the fan-out workers ignore until approved, and every hydration checks that the viewer may see the author's posts, with the check cached per (viewer, author) for a short time so it does not add a lookup per post on every feed load.
6. What a strong answer sounds like
- Lead with the two big numbers: 3.5 GB/s in and 230 GB/s out, and the design that follows (direct uploads, immutable renditions, CDN).
- Make the post visible before processing completes and explain how the states are reconciled.
- Reuse the hybrid fan-out feed and point out explore is a different read path with its own failure domain.
- Handle the viral post's counters and comments explicitly.
- Expect follow-ups on video (segmented transcoding and adaptive playback), on deleting a post from CDN and inboxes, and on privacy (private accounts and follower approval changing what fan-out may push).
- Common mistake: proxying uploads through the API tier, or storing counters as a single row per post.
02Where this question was reported
- IGotAnOffer · EM: photo sharing website with upload/edit/download and thumbnails
- IGotAnOffer · 'Design a photo-sharing app'
- IGotAnOffer · 'system for uploading and tagging pictures'
- System Design Handbook · 'Google Photos or a Media Storage Platform'
- interviewkickstart.com · 'your version of Instagram'
- DesignGurus · 'Designing Instagram'
- PracHub · PM: cutting Google Photos' storage footprint
- Blind · Ephemeral stories
- Medium · Rushed Design Instagram round led to rejection (search snippet)
- Blind · Commenter: Google may also ask a standard 'design Twitter'.
- interviewkickstart.com · 'Your version of Instagram / Twitter'; 'Twitter search'.