The 100 problems, solved / Video and media / 036 · Design TikTok

Design TikTok

Short videos, an endless personalised For You feed, and uploads that go live in seconds.

Concepts this design leans on

01The design, in the six-step framework

1. Requirements

Functional

  • Upload a short video (under 3 minutes); it is playable within seconds.
  • An endless personalised For You feed that starts instantly and never stalls.
  • Likes, shares and follows feed back into what is shown next.
  • Out of scope: live streaming, in-app editing effects, creator payments.

Non-functional

  • 1 billion monthly users; 100 million concurrent at peak; 50 million uploads a day.
  • First video of a session plays in under 500 ms; the next video is preloaded before the swipe.
  • Feed freshness: a new upload can appear in feeds within minutes.
  • Engagement signals influence the next request, not just tomorrow's model.
  • Playback availability 99.99 percent; the ranking model may degrade to a popularity fallback.
Back of the envelope

50 M uploads a day at 30 MB average source = 1.5 PB a day of raw uploads, encoded into about 3 PB of renditions (several short renditions per clip).

Feed requests: 100 M concurrent users swiping every 15 s = 6.7 million feed decisions per second at peak, each returning a page of about 8 videos.

Ranking 6.7 M requests a second against hundreds of candidates each is 1 to 2 billion model scorings a second, which is why the pipeline is staged: cheap retrieval first, an expensive model only on the final few hundred.

Playback: 100 M viewers × 2 Mbps = 200 Tbps from the CDN at peak.

2. Core entities

  • Video: video_id, creator_id, caption, sound_id, renditions, state, created_at.
  • User: user_id, country, follows, interest embedding (updated continuously).
  • Engagement event: user_id, video_id, type (watch time, like, share, skip), timestamp.
  • Candidate set: per-user cached list of ranked videos not yet shown.
  • Video embedding: video_id, vector, popularity stats, freshness.

3. API

  • POST /videos and resumable chunk upload; returns video_id. Called by the creator's app.
  • GET /feed?session=…&count=8: the next page of videos with manifest URLs. Called by the viewer's app.
  • POST /events: a batch of engagement events from the last few seconds (watch time, like, skip). Called by the app.
  • POST /videos/{id}/like, POST /users/{id}/follow: explicit actions.
  • GET /users/{id}/videos: a creator's profile grid.

4. High-level design

ClientsEdgeServicesDatafeed, eventscandidatesfeatureseventsupdateplaymissembedAppCDNFeed APIRanking pipeline(retrieve, score, rerank)Upload + transcodeFeature + embeddingserviceVector index(ANN)Video objectsEngagement events(stream)Video + user metadata

One swipe:

  1. The app asks the feed API for the next page, sending the session id; the API also receives the last few seconds of engagement events in the same call.
  2. The ranking pipeline retrieves a few hundred candidates: nearest neighbours of the user's interest vector from the ANN index, fresh uploads from followed creators, and trending videos in the user's region.
  3. A scoring model predicts watch time and interactions per candidate using features from the feature service; a reranker enforces diversity (not three videos with the same sound) and business rules.
  4. The API returns 8 videos with manifest URLs; the app starts the first from the CDN and preloads the next two.
  5. Engagement events stream in; a streaming job updates the user's interest vector and the video's popularity stats within seconds, so the next page already reflects a long watch or a quick skip.

5. Deep dives

How does the feed react to a skip within the same session?

Training a model nightly means today's skips change nothing until tomorrow, and users notice. Two feedback loops run at different speeds: the user's interest vector is an exponentially weighted average of the embeddings of videos they watched, updated by a streaming job within seconds and read by retrieval on the next request; the scoring model itself is retrained hourly or daily on the event stream. The session-level loop is cheap arithmetic on vectors; the model loop is where quality comes from. Per-request, the app also sends events in the feed call so the server sees the skip before choosing the next page.

How does a brand-new video with zero engagement get shown?

OptionBehaviourTrade-off
Popularity onlyNew videos never surfaceCreators leave; the feed goes stale
Content embedding from the video itselfAudio, caption and visual features give a vector before anyone watchesRetrieval can match it to interested users immediately; quality of the vector matters
Explore slotsReserve one slot per page for fresh or uncertain videos, shown to a small test audience firstCosts a little engagement per page; the early signals decide whether to widen distribution

Both: an embedding at upload time for retrieval, plus explore slots so that every upload gets a few hundred impressions and the stream job promotes the ones that hold attention.

How is the next video always ready before the swipe?

Latency is hidden rather than eliminated. The app holds a buffer of ranked videos and preloads the first segment of the next two from the CDN, so a swipe plays from local bytes; the feed request for the next page is issued when the buffer drops below four, not when it is empty. Short videos are encoded into small renditions with a tiny first segment, so even a cold start is one small CDN fetch. The ranking service keeps a per-user candidate cache of a few hundred already-scored videos so that most page requests are a cache pop plus a quick rerank, and a full retrieval runs in the background every few pages.

Why does a 3 PB per day transcode not delay publishing?

Clips are short, so each transcode job is seconds, not hours, and the lowest rendition is produced first so the video is playable within about ten seconds of upload; higher renditions follow. The embedding job runs in parallel with transcoding on the source so that retrieval can find the video as soon as it is playable. Uploads are rate limited per account to keep abuse from consuming the encoder fleet.

Where does fan-out appear, if the feed is pulled?

The For You feed is fan-out on read: nothing is pushed to inboxes, the ranking assembles each page. The following feed is small and is served the same way from a per-creator recent-videos list, since a user follows at most a few thousand creators; a cache of each creator's last 20 videos makes it one batched read. Fan-out on write is not needed anywhere, which is the big simplification compared with a chronological social feed.

6. What a strong answer sounds like

  • Name the staged pipeline, retrieval then scoring then reranking, and say why it must be staged: billions of scorings a second otherwise.
  • Quote 6.7 million feed decisions a second, 200 Tbps of playback and 3 PB a day of encodes, and say which component carries each.
  • Explain the two feedback loops with their time scales and the cold-start answer for new videos.
  • Expect follow-ups on how to measure feed quality (A/B tests on watch time), on moderation before distribution, and on regional isolation of trends.
  • A common mistake is to design a Twitter-style fan-out on write; a ranked feed is assembled at read time.

02Where this question was reported

  • codinginterviewsmadesimple.substack.com · YouTube mock 'System Design Mock Interview: Design TikTok ft. Google TPM' (Exponent); interviewer explained TikTok's core functions, then asked what the candida