A former Google/Uber engineering manager (Mark) tackles “design TikTok” as a mock candidate, and the value is as much in his estimation discipline and communication as in the architecture itself. The interview walks the full arc from scoping and back-of-envelope math to blob/metadata storage, CDN-based streaming, and a candid, hand-waved attempt at the algorithmic For You feed.

Scoping the problem and picking success metrics

The first move was to shrink the question to something buildable in an hour. Mark and the interviewer agreed to ignore the mobile app and in-app content creation (duets, filters, trimming) and instead focus on the backend distributed system that supports video uploads and downloads. They also explicitly skipped sign-in/sign-up as too standard to be worth the time. The interviewer’s coaching note reinforces this: confirming and narrowing scope up front frees time for the parts that let a candidate actually impress.

For success metrics, Mark settled on time in app as the single simplest signal to maximize, assuming an average of roughly one hour per user per day. He floated a thoughtful product idea (maximizing time outside work/school hours for online-health reasons) but deliberately parked it as a future enhancement rather than derailing scope.

Scale estimation and how storage drives the design

Mark grounded the design in explicit numbers: one billion users across 150 countries, one billion video views per day, and ten billion videos uploaded per year. He set working assumptions of vertical 1080x1920 video, an average clip of about 10 seconds, and roughly 1 MB per video.

Storage math came first and dominated the thinking. Ten billion videos per year times 1 MB each works out to about 10 petabytes of raw video per year. Factoring in replication for redundancy and multiple device-specific encodings (a rough x10), he landed on roughly 100 PB per year of video storage. That figure is what pushed him toward a blob/object store rather than anything relational. Separately, video metadata (ID, creation time, duration, likes) at about 1 KB per video is a factor of a thousand smaller, so around 10 TB, which he mapped to a NoSQL key-value store since videos don’t need to relate to each other.

Traffic math showed I/O is not the bottleneck. Ten billion uploads a year divided by 365 days and then ~100k seconds/day gives about 300 uploads/second average; applying a x3 peak factor gives ~1,000 uploads/second. At ~1 MB (~10 megabits) each that is only ~10 Gbit/s ingress, comfortably inside modern 10 GbE NICs. The read side is a factor of ten heavier: one billion views/day is ~10,000 videos/second, so ~100 Gbit/s egress, still workable. The coaching note flags one process miss: Mark jumped from storage to traffic without finishing the user-data storage estimate (~1 billion users x ~10 KB ≈ ~10 TB), and storage numbers are usually what most shape the design, so finish them first.

High-level architecture and service separation

The request path runs from the TikTok app through a load balancer (deliberately not dwelt on) into backend services. Mark split the front-end services in two along the two core use cases: an application/content service that serves the feed and everything a user sees on open, and a separate upload service for creating videos. He justified the split on microservices grounds since the two serve different purposes and scale differently.

Behind those services sit three storage systems. Raw video lives in blob storage, metadata in a NoSQL store, and user/social-graph data in a relational store. He was upfront about a bias toward managed/hosted cloud services (S3, DynamoDB, RDS, or Cloud Spanner) for an initial build, reasoning as an engineering manager that they offload operational and maintenance burden so engineers don’t reinvent blob storage or indexed key-value stores, even if it costs more early on.

Video storage, tiering, and CDN-based serving

Raw videos go to blob storage, concretely Amazon S3, chosen because it scales well and is purpose-built for large objects with easy replication and regional replicas. Mark introduced tiered S3 storage as a cost lever: assuming most TikTok videos have a lifespan of only a couple of months and old clips are rarely rewatched, aged/untouched videos can migrate to slow, cheap cold storage. Video metadata goes to a NoSQL store such as DynamoDB (or Cloud Spanner), wrapped conceptually with the blob store into a single “video storage database.” User data is treated differently: because of the social graph (followers, connections spanning regions), he wanted it in a relational store like RDS or Cloud Spanner rather than partitioned into isolated shards that can’t talk to each other, while noting a billion users at ~1 KB (~1 TB) starts to approach relational scaling limits.

Serving is the interesting half. Videos are delivered through a CDN (e.g. CloudFront), a layer of caches close to users. On a request the CDN serves the video directly if it’s cached (fast for popular clips); on a miss it fetches from S3, serves it, and decides whether to cache. On the interviewer’s regional question, Mark described two levers: locating data centers/partitions near users (by region or language) for responsiveness in India, Europe, China, etc., and letting the CDN naturally keep region-popular videos cached locally, so India-created videos end up cached in Indian edges. He was honest that he wasn’t yet sure how explicitly he’d partition by region.

Upload and streaming data flows

The upload flow is deliberately simple: the app sends a video to the upload service, which writes the raw bytes to blob storage and the descriptive record to the metadata store, so the system knows the video exists and whether it can be shown. He noted that encoding into multiple device-optimized formats would happen here, likely offline/asynchronously, producing several blobs and URLs per video.

The streaming/download flow has two distinct channels, and keeping them separate was the key insight. When the app opens, the application service calls the For You generator, which returns a list of video IDs (plus users and profile data) for that user. The service resolves those IDs against the metadata store to get per-video info including the URL (the S3/blob location), creator, likes, and duration, and returns that structured payload to the app. The app then fetches the actual bytes directly from those video URLs, which hit the CDN. So metadata (small, structured) travels through the application service, while the heavy video payload flows separately through the CDN and blob storage. Authentication and HTTPS were explicitly hand-waved.

The For You feed: ML generation plus rule-based guard rails

Mark framed the personalized For You feed as the hard, magic part and modeled it as a “For You generator” service (replicated for scale) that the application service queries on every request. He argued a hand-crafted rule-based system (“if this many likes, then show”) would quickly become unmaintainable, so he’d use machine learning: videos are feature-extracted offline and used to train a model, and at request time the model matches a per-user profile against the catalog to pick videos.

He extended both schemas to support this. Video metadata gains algo/feature fields (length, content, location, language); user data gains a For You profile of features (following graph, content preferences, language) plus watch history, uploaded video IDs, following IDs, and the time-in-app success metric. His most practical observation: this ML pipeline is slow and asynchronous, so user actions that must take effect immediately (unfollowing someone, “don’t show me this”) can’t wait for it. He added a rule-based exclusion profile of guard rails (blocked follower/user IDs) applied either in the app service or pushed down into the generator, combining imperfect ML with unambiguous rules to produce the final filtered list of video URLs. He was candidly upfront that ML is outside his expertise and he was oversimplifying, which the coaching note praised as the right way to handle unfamiliar-but-required components.

Bottlenecks, enhancements, and communicating tradeoffs

Asked about bottlenecks, Mark distinguished a storage bottleneck (all user data in one relational table, possibly forcing partitioning by largest regions) from a performance bottleneck, which he located in the For You generator running in near real time on every request. He explained TikTok’s zero-lag feel via read-ahead: the app continuously pre-fetches the next 10-20 videos in the background so playback starts instantly on scroll. His headline scaling idea was to move the generator’s inference out of the cloud and onto the device for the most popular platforms (iOS/Android), exploiting powerful phone GPUs to offload compute from the distributed system. The coaching note singled this out as a strong, powerful option for mobile.

For enhancements he offered two. A product one: occasionally “peppering” the feed with content outside the user’s interests to test new algorithms and broaden exposure, still passing through the exclusion guard rails. A systems/cost one: once the architecture stabilizes, replace expensive managed services (DynamoDB, RDS) with self-hosted MySQL or similar where scale makes the engineering cost worthwhile, an explicit service-cost-versus-engineering-cost tradeoff. The coaching closed by noting the peppering idea is more product than system, and that a candidate should match depth to the role: more technical depth for IC roles, more cost/tradeoff reasoning for engineering-manager roles as Mark showed.

Key takeaways

  • Scope aggressively up front: cut the app, content creation, and login to focus on upload/download; confirm every scoping call with the interviewer.
  • Let estimation drive architecture. ~100 PB/year of video (raw x replication x encodings) points to blob storage; ~10 TB of metadata points to NoSQL; ingress ~10 Gbit/s and egress ~100 Gbit/s are not bottlenecks.
  • Finish storage calculations before moving on; they most influence the design (Mark skipped the user-data estimate).
  • Separate the two serving channels: small structured metadata via the app service, heavy video bytes via CDN + blob store fetched directly by the client.
  • Use tiered/cold storage for aged videos given short content lifespans, and a CDN for region-local popular-video caching.
  • Split blob (S3), metadata (DynamoDB/Spanner), and relational social-graph data (RDS/Spanner); keep the social graph relational rather than isolated shards.
  • Model the For You feed as offline-trained ML returning video IDs, backed by real-time rule-based exclusion guard rails for actions that must apply instantly.
  • Explain the no-lag UX via client read-ahead of the next 10-20 videos.
  • Consider offloading inference to on-device GPUs on popular mobile platforms to relieve the generator bottleneck.
  • Interview technique: prefer managed services for a first build and justify it as an EM; be honest about gaps (ML) while still engaging simplified; match technical-depth vs cost-tradeoff emphasis to the target role.

Sources