01What drives who shows up in my stack — preferences, distance, or both?
Users set preferences (age range, interests) and a maximum distance; the stack only contains candidates satisfying both.
Free full guide
Design Tinder — a location-based dating app with swipe feeds, mutual-match detection, and recommendation of nearby profiles.
The interview rhythm stays compact, so the page can spend attention on the actual design decisions.
Do not only state requirements. Ask for them. Each card pairs the design constraint with a clarification question you can say out loud before drawing the architecture.
01What drives who shows up in my stack — preferences, distance, or both?
Users set preferences (age range, interests) and a maximum distance; the stack only contains candidates satisfying both.
02Is swiping one-at-a-time, and can a profile ever come back?
Users swipe yes/no one profile at a time, and a swiped profile never reappears — repeat profiles read as broken.
03What happens at the moment of a mutual yes?
Both users get the match notification immediately — mutual-match detection is strongly consistent, not a batch job.
04Can a user undo a left swipe (rewind)?
Within a short window, yes - and since a Bloom filter cannot unlearn, recent swipes also live in a small exact ring buffer that rewind edits.
05What does unmatching do?
Unmatch tombstones the match and revokes the chat atomically - a half-revoked match (chat alive, match gone) is a trust bug.
06A user changes preferences mid-session - what happens to their deck?
The precomputed deck invalidates immediately and refills against the new filters - serving the stale deck violates explicit user intent.
Out of scopePhoto upload pipeline · Messaging after a match · Premium features (super swipes, boosts)
01Two people swipe yes on each other in the same second — what must be true?
Exactly one match, detected immediately: the two swipe records and the mutual check must not interleave.
02What swipe volume are we sizing for?
20M daily active users (DAU) × ~100 swipes ≈ 2B swipes/day — about 23K swipes per second on average.
03How fast must the stack appear?
Under 300 ms — which forces precomputed decks; a live geo+preference query cannot hit that.
04How hard is the "never show twice" rule?
Hard: it must hold across sessions and cache failures — a false "not seen" is worse than quietly skipping one candidate.
05What location data can other users ever see?
Only a coarse distance bucket ("~5 km away") — raw lat/lng never leaves the backend, in any payload.
Real interviews probe far more than a tidy list. These are the scope questions that separate candidates who interrogate the problem from those who recite it.
Treat every estimate as a pressure that justifies a component: cache, queue, partition, replica, worker pool, or fallback path.
Swipe write rate
20M daily active users (DAU) × ~100 swipes/day2B ÷ 86,400 s ≈ 23K swipes/s average, evenings ×3-5 ≈ 100K/s peak
Swipes need a write-optimized store; the mutual check must stay O(1) per swipe at this rate.
Seen-profile memory
A heavy user swipes 50K profiles over a lifetimeBloom filter at 1% false positives ≈ 10 bits/entry → 50K × 10 b ≈ 62 KB per user
The entire "never show twice" guard fits in kilobytes per user — the exact swipe history stays on disk.
Deck precompute cost
Deck of 200 candidates per active user, refreshed when low20M users × 200 IDs × 8 B ≈ 32 GB
Precomputed decks for every active user fit in one cache tier — that is what makes <300 ms feasible.
Why not query live
Geo + age + preference + not-seen filter across millions of nearby usersmulti-index intersection + exclusion list per request ≫ 300 ms budget
The feed budget forces precompute-plus-top-up; the live query runs in the background, not on the request path.
Match check cost
Every yes-swipe checks the reverse direction1 atomic read-modify-write per swipe ≈ sub-ms in memory
Keeping the pair’s swipe state co-located (one key) is what keeps the check one operation.
Decision example
A hundred thousand swipes a second at peak, and the one moment that cannot go wrong is two people saying yes to each other simultaneously.
I would co-locate each pair’s swipe state under one key (the two user IDs, smaller first) and run the swipe-plus-mutual-check as one atomic operation — a Lua script in Redis does the read-modify-write in one step, with the durable copy written to the swipe store behind it. Decks are precomputed per user and topped up by a background geo query; each user’s seen-profiles live in a Bloom filter, so "never show twice" costs kilobytes, not a history scan.
What I would NOT do: record the swipe and check the reverse in two separate steps — two simultaneous yes-swipes each miss the other and the match never fires. That check-then-act gap is the same race that double-sells concert seats; the check and the write must be one operation. I also would not build the feed as a live geo query per request — the 300 ms budget dies in index intersections.
If Redis operations become the bottleneck or cluster failover complexity bites, I would move the atomicity into the storage layer: a compound partition key (smaller_id:larger_id) makes both swipes land in one partition where a lightweight transaction (the database’s own compare-and-set — slower, but built in) covers the pair — slower per swipe, one fewer moving system.
Draw the write path and the read path as separate lanes — they carry different traffic and justify different components.
The swipe path is the consistency-critical spine; the feed path is read-optimized and precomputed. Dashed = maintained asynchronously from durable swipes, rebuildable after cache loss.
One atomic operation records the swipe and checks the reverse. The durable write follows; a Redis node loss replays from the durable store, losing at most the last moments of unflushed swipes — an accepted trade for swipe-path speed.
The request path only reads the deck. When it runs low, the background query refills it, excluding seen profiles via the Bloom filter — false positives skip a candidate, never repeat one.
Before optimizing, make the contract inspectable: endpoints, entities, ownership, retries, and state.
POST/profile
req{ age_min, age_max, distance_km, interested_in }
res200 profile
Identity from the session token. Preference changes invalidate the precomputed deck.
GET/feed
res200 User[] (next slice of the deck)
Serves the precomputed deck; when it runs low, a fresh geo+preference query tops it up. Location comes from the session context, not query parameters.
POST/swipe/{target_user_id}
req{ decision: yes | no }
res200 { matched: boolean } — matched:true fires both notifications
The atomic step: record the swipe AND check the reverse swipe as one operation.
Core entities
Useruser_id (PK) · profile · preferences · geo_cell (coarse)
Location is stored as a coarse geo cell for matching; precise coordinates are never served to other clients.
Swipeswiping_user · target_user · decision: yes/no · swiped_at
Written durably to the swipe store; also folded into the swiper’s Bloom filter of seen profiles.
Matchmatch_id (PK) · user_a · user_b · matched_at
Pick one lane for the final third of the interview. Each lane gives you the topic, the interviewer question it should answer, and the failure mode to avoid.
FocusThe simultaneous yes
AskTwo users swipe yes on each other in the same 10 ms. Walk the exact operations that produce one match, not zero.
AvoidRead-then-write in two steps — both swipes miss each other and the match silently never happens.
FocusNever show twice
AskHow do you exclude 50,000 already-swiped profiles from every deck refill without scanning history?
AvoidTreating Bloom false positives as a bug — skipping one candidate is the designed cost; repeating one is the failure.
FocusThe deck runs dry
AskAn active user swipes through their whole precomputed deck. What refills it, how fresh is it, and what latency do they see?
AvoidRefilling synchronously on the empty-deck request — the 300 ms budget is gone before the query starts.
FocusLocation without leaking it
AskMatching needs distance, users must never see coordinates. Where does precision get dropped, and what does the API actually return?
AvoidSending raw lat/lng to clients and rounding in the UI — the payload is the leak.
FocusEveryone swipes the same person
AskA very popular profile appears in millions of decks. What hot-spots first, and how do you keep exposure balanced?
AvoidIgnoring exposure skew — without caps, popular profiles dominate every deck and engagement collapses.
Talk through Tinder out loud and get AI scoring on the explanation.