Software Engineers at Discord work on a platform for real-time voice, video and text communities. The work depends on which team you join. It ranges from core infrastructure and persistence (running distributed datastores, scaling message indexing, tuning socket connections and latency) to safety processing pipelines, monetization features such as Quests, and web and mobile clients built in React and React Native. Be ready to talk about features you owned end to end, from design and trade-offs to deployment and on-call.
The reported stack is Python, Rust, Go, TypeScript, React, React Native, ScyllaDB, PostgreSQL, Kafka and etcd, and the reported stack also includes Redis, ElasticSearch, Docker and Kubernetes. You do not need all of them. For live coding, use the language you write fastest in. Be ready to compare a relational store with a wide-column store for high-write message data. Know a coordination service like etcd well enough to explain leases, TTLs and failover.
Candidates say the interview favors practical engineering over abstract puzzles. Candidates report coding in their own local IDE over screen share. Reported prompts include a multi-client TCP or WebSocket chat server, an etcd-based leader-follower cluster, a matchmaking design, sessionizing event logs, and walking through a CPU spike or dropped connections. The question bank still lists algorithmic items such as KMP string matching, DFS backtracking and trie-based completions. Keep some data-structure practice in your week, but put the hands-on work first.
Recruiter Screen
reportedThe recruiter screen is reported as a conversation about your background and fit for the role. Use it to get the facts that shape your preparation. Ask which team or domain the role sits in; reported team areas range from Core Infrastructure and Persistence to Safety Processing, Monetization and Client Platform. Ask whether the technical screen is a hands-on build in your own IDE, which languages are accepted, and what tools you may use in coding rounds. State your hard constraints (start date, location, work authorisation, competing timelines) now so none of them comes up late.
What to demonstrate
- Whether your background fits the team area the role is hiring for
- Whether you can summarise your recent work in a few sentences and name the scope you owned
- Whether your constraints and timeline fit the process
How to prepare
- Write a short summary of your last two roles that names the systems you owned, the language you used and one concrete result
- Ask which team the role belongs to and adjust your week: infrastructure teams point toward sockets, etcd and storage, and client teams toward React components and real-time state
- Ask whether coding happens in your local IDE, which languages are fine, and whether documentation or AI assistants are allowed in each round
Hiring Manager Call
reportedCandidates describe this as a call with the hiring manager to align on expectations and on your qualifications. Treat it as a shorter version of the project retrospective, since the conversation is about whether your experience maps to the team's work. Bring one or two projects you can explain as decisions: why that datastore, why that concurrency model, what you traded off and what failed. Connect them to the team area the recruiter named. End with questions about what the team is building and how on-call works.
What to demonstrate
- Whether your past work maps to the team's domain, such as infrastructure, safety processing or client platform
- Whether you can explain decisions you owned, the alternatives you rejected and why
- Whether you can explain trade-offs clearly to someone who did not work on the project
How to prepare
- For each of two projects, write the decision you made, the option you rejected and the constraint that settled it
- Prepare one example of a technical disagreement and how you resolved it with evidence such as a benchmark or a prototype
- Prepare three questions about the team's current systems, its on-call load and the work planned for your first months
Technical Screen
reportedCandidates describe a 60-to-75-minute practical screen focused on hands-on live implementation in your own IDE over screen share. It often means building a working network application such as a multi-client socket chat server. The prompt usually grows: first a working broadcast, then follow-ups such as nicknames, listing online users, clean disconnects and system notifications. Practise getting a minimal version running and demonstrable with telnet or netcat, then extending it without breaking it. Before you write the code, explain your concurrency choice: threads with a lock, or an asyncio event loop.
What to demonstrate
- Whether you can start a TCP or WebSocket server from the standard library and demonstrate it with several clients
- Whether concurrent clients are handled safely: shared client state, broadcasts that skip the sender, and disconnects that do not crash the server
- Whether you get a working minimal version first and extend it cleanly as requirements are added
- Whether you explain your approach and debug errors out loud as you go
How to prepare
- Build the multi-client chat server twice from blank, once with threads and once with asyncio, and test each with three telnet sessions
- Add the reported follow-ups one at a time: a nickname on connect, a command listing online users, join and leave notices, and handling a client killed mid-message
- Frame input on newlines so you handle a message split across two reads, and two messages arriving in one read
- Rehearse the setup: project open, run command ready, loopback ports allowed through the firewall
Virtual Onsite Loop
reportedCandidates report the onsite as four to five virtual interview blocks covering live coding, system design, incident troubleshooting, a project retrospective and values alignment. Team-specific loops can change individual topics. Prepare each block as a separate skill. For coding, expect the same practical style as the screen. For the design questions in this guide (matchmaking on skill, latency and wait time; message storage at very large scale on ScyllaDB or PostgreSQL; an etcd leader-follower cluster), state the requirement before you choose a component. For troubleshooting, practise a hypothesis-driven walk-through of a CPU spike or of dropped connections. For the retrospective, prepare one project in depth.
What to demonstrate
- Whether design answers start from requirements and name trade-offs, such as a partition key for message data and the queries it makes expensive
- Whether your debugging walk-through asks for evidence, separates mitigation from root cause and names what each check rules out
- Whether a project retrospective holds up under follow-ups about missteps, edge cases and friction with other teams
- Whether live coding keeps the same working-first approach as the technical screen
How to prepare
- Talk through the matchmaking design aloud: queues per region and skill tier, how the allowed skill gap widens with wait time, and what happens when a match forms but a player drops
- Model message storage for a chat app: partition by channel and time bucket, order by a time-sortable message id, and say what that design makes hard, such as cross-channel search or hot channels
- Write a one-page incident checklist (what changed, which metrics, blast radius, mitigation, root cause, follow-up) and run the CPU-spike prompt against it
- Prepare the retrospective and values stories listed in the behavioral section
11 candidate reports. Individual accounts describe a particular role and hiring cycle.
Discord Software Engineer interview with socket and chat server coding
I went through an uneven Discord process. The technical experience felt rushed, poorly explained, or overly constrained, and it didn't end in an offer. The recruiter and hiring manager lead-in was relatively smooth in tone, although expectations weren't always communicated well. In the technical screen and live coding round, I worked on socket or chat server style problems under time pressure, wi…
Read full experienceDiscord Software Engineer interview: technical screen felt pointless
I had a Discord interview where I followed the instructions closely but still didn't progress, which left me frustrated with the technical screen. The recruiter screen involved slow scheduling and initial coordination. During the technical screen, I solved and handled what the interviewer asked, but the conversation felt "pointless," with little discussion or flexibility. Although I had a good te…
Read full experienceDiscord Software Engineer interview: relaxed recruiter screen
I had a low-stakes, recruiter-first experience for a Software Engineer role, with a quick and mellow timeline. The recruiter screen was a relaxed conversation about my background and why Discord. We also discussed the team and the hiring motivation, and the overall mood was friendly and calm. I didn’t receive an offer. The stage felt easy and conversational, but it didn’t lead to any further move…
Read full experienceDiscord Software Engineer interview: technical questions in the first screen
I had an early-stage Discord interview that combined recruiter outreach with technical and behavioral questions, but it didn't progress further. After I was emailed to apply, I scheduled a screening call. I answered technical questions along with standard behavioral questions. I didn't receive an offer, and the experience showed me that the first screen could include hands-on technical checking r…
Read full experienceDiscord Software Engineer interview: React component live coding
I interviewed for a Software Engineer role with a front-end-focused live coding component that let me work interactively on screen. The recruiter screen was a short phone call about my background. For the live coding round, I had to design and implement a relatively small React component while sharing my screen. In one case, the interviewer helped keep the expectations clear, and we had a back-an…
Read full experiencePracHub editorial advice for the preparation topics above.
Spending the start of the technical screen on local setup
Candidates report coding in their own IDE over screen share, so any setup problem costs you time in front of the interviewer. The day before, open a fresh project in the language you will use, start a TCP listener on localhost, connect two telnet or netcat sessions, and confirm your firewall allows loopback connections. Bookmark the standard-library docs for sockets, threading and asyncio, and have the command that runs your server ready.
A chat server that crashes or misbehaves when a client leaves
The reported chat prompts ask for a broadcast that does not echo to the sender, and for clean disconnects. The usual bugs are writing to a closed socket (broken pipe) inside the broadcast loop, changing the client set while iterating over it, and treating one recv() as one message. Get the plain broadcast working first. Then handle a zero-byte read and write errors by removing that client under a lock or inside the event loop, and frame input on newlines. Test with three terminals, killing one mid-session, before you add nicknames or user lists.
Leader election that only works on the happy path
In the etcd leader-follower prompt, electing a leader is the easy half. Explain how leadership is held (a lease with a TTL that the leader keeps alive), what followers watch to detect its loss, and what happens when an old leader pauses past its TTL and resumes still acting as leader. Name the guard, such as checking the lease or a revision before acting, and show followers redirecting traffic to the current leader. When you practise, kill the leader process and measure how long failover takes.
Naming a fix before gathering evidence in the incident walk-through
For reported prompts like a CPU spike after a routine deployment, or dropped sockets during a connection burst, first ask what changed and when, which metrics and logs you can see, and who is affected. Then name a cause. Keep mitigation (roll back, shed load, rate limit) separate from root cause, and say what each piece of evidence rules out. Network saturation, thread-pool exhaustion and database lock contention each leave a different signature.
A project retrospective with no decisions of your own and no mistakes in it
Follow-ups in a retrospective can go into architectural missteps, edge cases you missed and friction with other teams. Write the project as a timeline of decisions you made, with the option you rejected at each point, one thing that went wrong and what you changed, and one result you can measure. Replace team-level summaries with a clear statement of your own part.
Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.
Choose the fanout threshold that fits a daily write budget
You have one day of publishes as (author_id, publish_count) for up to 40 million authors, plus each author's follower_count, which reaches 10^8. Under push fanout a publish costs one timeline write per follower; under pull it costs zero. A threshold T makes every author with follower_count at or above T pull, and everyone below it push. Given a daily budget B of timeline writes, return the largest T that keeps total writes at or below B, and the fraction of publishes served by pull at that T. The obvious solution is correct; say why it is too slow, then replace it.
Approach
- Price the naive method precisely instead of waving at it. Evaluating one candidate T is a full O(A) pass summing publish_count times follower_count over authors below T; sweeping every possible follower value is up to 10^8 candidates, so it is O(A * 10^8), and even restricting candidates to the distinct observed follower counts leaves O(A^2) in the worst case. It is correct and it will not finish.
- Establish monotonicity and get its direction right: raising T moves more authors into push, so total writes is non-decreasing in T. That is why the question asks for the largest T within budget rather than the smallest; the smallest is trivially the one where nobody is push, and it wastes the read path.
- Sort authors by follower_count once, O(A log A), and build a prefix sum of publish_count times follower_count over that order. total_writes(T) is then one array lookup at the boundary index for T, and the answer is the last prefix entry at or below B, found by a single linear scan of the prefix array. No binary search is needed unless you must answer many budgets against the same day.
- Watch the arithmetic width, because it decides the answer rather than merely the tidiness. Per-author products reach 10^10 and the running total passes 2^53, above which a float64 no longer represents consecutive integers, so accumulating in doubles moves the chosen T. Use 64-bit integers and say so.
- Compute the pull publish fraction from a second prefix sum over publish_count alone, taken in the same sorted order and the same pass, so the two answers cannot disagree about where the boundary sits.
- State the limit of the result: this optimizes the write budget only. The read path pays a k-way merge per viewer proportional to how many pull-mode accounts that viewer follows, so T must also be checked against the worst-case following count, and the usable answer is the intersection of both constraints. Add that because follower counts are heavy-tailed, the prefix curve is nearly flat and then jumps, so T is insensitive over a wide range and then abruptly sensitive: report the curve, not just the number.
Follow-up
- Writes per day is the wrong unit, because the queue fails on instantaneous backlog rather than a daily total. How do you restate the budget, and what does that do to the data you need?
- T changes. What happens to the timelines already materialized for an author who just flipped to pull, and what is missing for one who just flipped to push?
- One author has 10^8 followers and publishes 200 times a day. Show what that single author does to your answer, and argue whether a global threshold is the right instrument for them at all.
Flag actors exceeding a rate ceiling in any sliding window
An event stream gives you (actor_id, action_kind, ts_ms) for engagement writes, already sorted by ts_ms: up to 200 million events over one day from up to 30 million distinct actors. Return every actor_id that at any point had more than K actions inside a window of W milliseconds, where K is at most 1000 and W at most 60000. The window slides continuously; it is not a fixed bucket. One pass over the stream. State time and space bounds, and say how memory stays bounded given that most of those actors are idle at any instant.
Approach
- Reduce the per-actor state to the minimum that can answer the question: you never need all of an actor's timestamps, only the K-th most recent one. Keep a K-slot ring buffer per actor; on each event, if the buffer is already full, compare ts against the oldest slot, and flag when the difference is within W, because that means K+1 events fall inside one window.
- Say why fixed tumbling buckets of width W are wrong rather than merely approximate: K events at the end of one bucket and K at the start of the next are 2K events inside a single W-wide window and never trip a bucketed counter. The undercount is structural, not a tuning issue.
- Bound memory by eviction, not by capacity: an actor whose most recent event is older than W can never contribute to any future window, so drop its buffer. Maintain a FIFO of (actor_id, ts) appended on every event and pop from the front while the front ts is older than now minus W, discarding an entry whose ts no longer matches that actor's latest event. That lazy-deletion pop is amortized O(1).
- Give the bounds in terms of the right variable: O(n) time overall, and O(A_w * K) space where A_w is the number of distinct actors active within any W-millisecond window, which at W = 60 seconds is orders of magnitude below 30 million. Quoting space as O(actors) instead of O(active actors) is the answer that makes this look infeasible when it is not.
- Fix the boundary convention before coding it. State whether the window is half-open, so that an event exactly W after the K-th previous one does not flag, and keep that convention identical in the eviction test, or the detector disagrees with itself at the edge.
Follow-up
- The stream is now unsorted by up to 5 seconds of clock skew. What breaks first, and what is the minimum buffering that restores a correct answer?
- You are given a fixed memory budget that may not grow with the active actor count. What structure do you reach for, and which direction does its error run: false flags or missed ones?
- The product wants the count of distinct content items acted on in the window rather than the count of actions. What in your per-actor state has to change, and what does that do to the space bound?
Size encoder concurrency and schedule transcodes for makespan
Transcode jobs are (asset_id, rendition_profile, ready_at_ms, duration_ms): up to 2 million a day, durations from 200 ms to 40 minutes. Part one: given a log of jobs that actually ran, each with (start_ms, end_ms) where the interval is half-open, report the minimum number of concurrent encoder slots that would have been needed and the first instant that peak was reached. Part two: given C slots, with no job starting before its ready_at_ms and no preemption, assign jobs in ready_at order and report the makespan. State the complexity of each part.
Approach
- Recognize part one as maximum interval overlap and solve it with a sweep over 2n signed endpoint events sorted by time: +1 at a start, -1 at an end, running sum, track the maximum and the first time it is attained. O(n log n) for the sort, O(n) space.
- Get the tie rule right, because it is the whole correctness of the sweep: with half-open intervals, an end at time t must be processed before a start at time t, otherwise every pair of back-to-back jobs inflates the peak by one and you over-provision the pool. Encode it in the sort key, not in a comment.
- Note the equivalent formulation with the same bound and less machinery: sort start times and end times into two arrays and two-pointer them, advancing whichever is smaller with ends winning at equality. Same O(n log n), constant extra space beyond the two arrays.
- Solve part two with list scheduling on a min-heap of C slot free-times: for each job in ready_at order, pop the earliest free time f, start at max(f, ready_at_ms), push back start + duration_ms. O(n log C) time, O(C) space, and the makespan is the maximum value remaining in the heap.
- Bound the claim you make about part two, because this greedy is not an optimizer: it reports the makespan of one specific, reproducible policy, the non-delay schedule induced by ready_at order, and that number can be strictly larger than what the same jobs achieved on the same number of slots in a real log. What is provable about it is an approximation bound. The last-finishing job j waits only when every slot is busy throughout [ready_at_j, start_j) -- no slot can idle there, since every job placed before j has ready_at at most ready_at_j -- so the total work is at least C * (start_j - ready_at_j) + duration_j. Combine that with OPT at least (sum of durations) / C and OPT at least ready_at_j + duration_j and you get makespan at most 2 * OPT - duration_j / C. The bound is close to tight: with all ready_at zero, C * (C - 1) unit jobs followed by one job of length C gives exactly (2 - 1/C) * OPT.
- Say what minimizing it would actually cost, so the greedy is a choice rather than an oversight: reordering to minimize makespan on C identical slots is NP-hard for C at least 2, since P2||Cmax contains PARTITION, and longest-processing-time-first is the classic 4/3 - 1/(3C) approximation for the case without release times.
- Connect the two numbers to the decision they inform: part one sizes the pool for a no-queueing service level, part two gives the drain time at a chosen C, and the gap between them is the queueing delay a publish-time rendition inherits, which is what the product actually feels. Do not close the loop by asserting that C set to part one's peak reproduces the log's end time. The log's own schedule may have used an assignment this greedy will not choose, so the greedy makespan at that C can be strictly larger.
Worked solution 25 min
- Build the 2n event array with the tie rule encoded in the sort key, run the prefix sum, and record both the maximum and the first timestamp achieving it.
- Verify by hand on [0,10) and [10,20), where the correct peak is 1, then on [0,10) and [5,15), where it is 2.
- Implement part two as a C-entry min-heap seeded with zeros, iterate jobs in ready_at order, and return the maximum residual free time.
- Check part two against the degenerate cases: C = 1 gives a serial schedule, and C greater than or equal to n gives max(ready_at + duration) over all jobs.
- Run the counterexample that stops you over-claiming: the log [0,2), [2,4), [0,3) has a peak of 2 and ends at 4, but those same three jobs as (ready_at 0; durations 2, 2, 3) through part two at C = 2 return 5. Then write the sentences that bound part two: one policy's makespan, at most 2 * OPT - duration_j / C, and NP-hard to minimize by reordering for C at least 2.
Follow-up
- Live publish renditions and a classifier reprocessing backfill share the pool. How do you keep the backfill from occupying every slot without letting slots idle when there is no live work?
- A job crashes at 90 percent and is retried. Does your peak-concurrency figure count that as one interval or two, and which does capacity planning want?
- Durations are estimates that can be off by 3x. Which of your two answers degrades under that error and which does not?
Make the like write idempotent and the counter conditional
engagement holds actor_id, content_id, action_kind ('like','save','repost','hide','report','not_interested'), idempotency_key UUID, created_at_utc, undone_at_utc and origin_surface, with UNIQUE (actor_id, content_id, action_kind). A phone on a flaky connection sends the same like three times, and the user later unlikes and re-likes. Write the exact statements for like and for unlike so the table ends in the right state and the item's like counter moves exactly once per real state change. State how the handler distinguishes an insert from an existing row, and what a duplicate-key violation means here.
Approach
- Do not read first. SELECT-then-INSERT races: both sessions see no row, both insert, and one fails on the unique index after the effect the user asked for already succeeded. The constraint is the mechanism that provides the property, not a backstop behind an application check.
- Like: INSERT INTO engagement (...) VALUES (...) ON CONFLICT (actor_id, content_id, action_kind) DO UPDATE SET undone_at_utc = NULL, idempotency_key = EXCLUDED.idempotency_key WHERE engagement.undone_at_utc IS NOT NULL RETURNING actor_id. A fresh like inserts, a re-like after an unlike updates and returns a row, and a duplicate of a live like matches nothing in the DO UPDATE predicate and returns zero rows.
- Gate the counter on that rowcount. An unconditional increment beside an idempotent insert reintroduces exactly the double count the constraint just prevented, which is why ON CONFLICT DO NOTHING without RETURNING is the wrong shape: it cannot tell you whether anything changed.
- Unlike is the mirror: UPDATE engagement SET undone_at_utc = now() WHERE actor_id = $1 AND content_id = $2 AND action_kind = 'like' AND undone_at_utc IS NULL, decrementing on one row affected. Never DELETE - the row is the ledger the counter is reconciled from, and deleting it also erases the evidence that the retry was a retry.
- Name the isolation dependency: ON CONFLICT DO UPDATE takes a row lock, so concurrent duplicates serialise. Under READ COMMITTED the loser proceeds against the winner's committed row; under REPEATABLE READ the same statement raises a serialization failure (SQLSTATE 40001) that the handler must retry rather than surface to the client.
- Call out the one case the triple does not cover: an unlike retried late, after a genuine re-like, matches on the triple and undoes the newer like. Bound it by retaining the key of the last state transition and rejecting a request whose key was already applied.
Worked solution 20 min
- Create the table with the unique constraint and seed one actor and one item.
- Fire the like statement three times in a row, recording the RETURNING rowcount after each.
- Run unlike, re-like, then like again, asserting undone_at_utc and the rowcount-gated counter after every step.
- Run two concurrent likes from separate sessions under READ COMMITTED and again under REPEATABLE READ, recording what each session gets back.
Follow-up
- The counter is one row on a viral item and the increment now blocks. Where does it move, and does the answer change the statements above?
- How long must idempotency_key be retained to cover client retries, and what does dropping it early cost?
- The same actor likes from two devices within 50 ms. Which statement wins, and does either client see an error?
Model the follow graph for both of its opposite reads
follow_edge holds follower_id, followee_id, created_at_utc, removed_at_utc, edge_state ('active','unfollowed','pending_request','blocked') and is_reciprocal. account holds follower_count and following_count. Two reads matter: which accounts a viewer follows, bounded by that viewer's following count, and who follows an author, unbounded and heavy-tailed. Give the primary key and every secondary index you need, and say why neither read can use the other's index. State exactly what a re-follow does to the existing row, and which of follower_count and is_reciprocal may be trusted for an authorization decision.
Approach
- Primary key (follower_id, followee_id). A B-tree leading on follower_id turns the viewer's followee list into one range scan returning k rows for a following count of k, and the same index cannot answer a followee_id lookup: with the leading column unbound the planner's only options are a full scan of the index or of the heap, on the largest table in the system.
- Add the reverse index (followee_id, follower_id) for the publish path. Make it partial on edge_state = 'active', because soft-deleted rows stay forever and fanout never wants them, with the precondition that the query repeats that predicate literally or the planner will not match the partial index. The cost is a second index entry per edge plus maintenance on every state change.
- A re-follow updates in place, because the primary key forbids a second row: INSERT ... ON CONFLICT (follower_id, followee_id) DO UPDATE SET edge_state = 'active', removed_at_utc = NULL. Decide what created_at_utc means and say it out loud - keeping the first-follow time means one row cannot hold the follow/unfollow history, and if that history is required it belongs in an append-only follow_event table with this row as its current-state projection.
- follower_count is a cache reconciled from this table, so an authorization test phrased as a count reads a number rather than an edge. Whether a viewer may see a followers-only item is an existence check against follow_edge with edge_state = 'active', which the reverse index answers in one lookup.
- is_reciprocal is written by whoever inserts the opposite edge, so it is stale for the window between the two writes and permanently stale if that writer failed. It is a display hint; maintain it in the same transaction as the opposite edge or drop the column and answer reciprocity with a lookup on the second index.
Follow-up
- Blocks live in this table as edge_state = 'blocked'. What breaks when a block and a follow must coexist between the same pair, and would you split blocks out?
- The fanout worker has to page a 40-million-row follower list. What is the cursor, and why not OFFSET?
- Reconciliation finds follower_count off by 12 for one account. Write the query that finds the drift, and say whether the drift ever means the edge table is wrong.
Design a high-throughput matchmaking system for a multiplayer online g…
Design a high-throughput matchmaking system for a multiplayer online game that pairs players based on skill tiers, latency constraints, and wait time.
Approach
- Name the failure you are designing for, then the recovery path.
- State the consistency you need, and where you are willing to be stale.
- Choose a partition key and say what query it makes expensive.
Follow-up
- How does this behave when that dependency is down for an hour?
- What breaks first when traffic grows ten times?
Implement a leader-follower distributed cluster using etcd key-value s…
Implement a leader-follower distributed cluster using etcd key-value storage where nodes perform leader election, periodic TTL updates, and automatic failover detection.
Approach
- State the consistency you need, and where you are willing to be stale.
- Name the failure you are designing for, then the recovery path.
- Name the read and write paths separately; they rarely have the same bottleneck.
Follow-up
- How does this behave when that dependency is down for an hour?
- What breaks first when traffic grows ten times?
Implement a interactive feature end-to-end, defining both state struct…
Implement a interactive feature end-to-end, defining both state structures and backend endpoints for real-time state synchronization.
Approach
- Clarify what is being asked and what a complete answer contains.
- Work from the requirement backwards to the design.
- Say what you would check first and why it is the highest-information step.
Follow-up
- What assumption would you test first?
- How would you know your answer was wrong?
Design and code a interactive Snake game or real-time game board handl…
Design and code a interactive Snake game or real-time game board handling state ticks, keyboard input events, dynamic collision boundaries, and thread-safe state rendering.
Approach
- Work from the requirement backwards to the design.
- Say what you would check first and why it is the highest-information step.
- State your assumptions explicitly before working the problem.
Follow-up
- What assumption would you test first?
- How would you know your answer was wrong?
Page a materialized home timeline with a stable cursor
A mobile client requests a viewer's home timeline, 30 items per page, at 500,000 page requests per second peak. Entries live in timeline_entry (owner_id, content_id, author_id, inserted_at_utc, sort_key, source) and new entries arrive at the head continuously while a viewer pages. Specify the pagination contract: the query for page one and for page N, what the cursor contains, the index that serves it, and what happens when two entries share a sort_key. A page must never repeat an item the viewer already saw or silently skip one.
Approach
- Rule out OFFSET on two separate grounds: it defines the window by counting from the start of a result set that mutates between requests, so k insertions at the head repeat k rows on page two and deletions skip the same number with no signal; and the engine must produce and discard OFFSET rows first, making page n cost O(offset + k) rather than O(log N + k).
- Define the cursor as the values of the last row returned, not a position: page one is ORDER BY sort_key DESC, content_id DESC LIMIT 31, page N adds the row-value predicate (sort_key, content_id) < (cursor_sort, cursor_content), which PostgreSQL can satisfy as a single index seek.
- Back it with an index on (owner_id, sort_key, content_id) so the ordering is produced by the scan and no Sort node appears. A uniformly descending read can be served by scanning that index backwards, so explicit DESC in the DDL only matters if the sort directions are mixed.
- Make the key unique within the owner: sort_key is the time-sortable content_id, and (owner_id, content_id) is already the primary key. A wall-clock timestamp collides at high insert rates, and at a tie the boundary row is either returned twice or dropped, which is exactly the failure keyset pagination was adopted to remove.
- Fetch limit + margin because visibility filtering removes rows after the read, derive has_more from whether the surplus survived filtering rather than from row count, and return the cursor opaque and signed so a client cannot forge a position into another owner's timeline.
Worked solution 20 min
- Write out both SQL statements and the CREATE INDEX that serves them.
- Trace page one returning rows with content_ids 900 down to 871, then insert five new entries at the head, then request page two under OFFSET 30 and under the keyset predicate, and list what each returns.
- Construct a tie: two entries with the same sort_key at the page boundary, and show which row is lost under a single-column cursor.
- State the cursor encoding and what makes it tamper-resistant.
Follow-up
- The viewer pulls to refresh and wants items newer than the head of page one. What is the query, and does it share the cursor contract?
- Replace sort_key with a ranking score that is recomputed between requests. Which part of the guarantee survives and which does not?
- The timeline store is wiped and rebuilt while a client holds a cursor. What does that client see on its next request?
Evaluate C++ memory alignment padding issues or ABI binary interface c…
Evaluate C++ memory alignment padding issues or ABI binary interface compatibility challenges when maintaining client library runtimes.
Approach
- Establish what changed and when, before forming any theory.
- Pick a bisection that eliminates candidates whichever way it turns out.
- Check the instrumentation before believing the symptom.
Follow-up
- What would you add now so this is faster to diagnose next time?
- What would you look at first, and what would it rule out?
Analyze a system failure involving broken socket pipes, network drops,…
Analyze a system failure involving broken socket pipes, network drops, or thread deadlocks during high concurrent connection bursts.
Approach
- Separate the trigger from the cause; the deploy is rarely the bug.
- Check the instrumentation before believing the symptom.
- Pick a bisection that eliminates candidates whichever way it turns out.
Follow-up
- What would you look at first, and what would it rule out?
- What would you add now so this is faster to diagnose next time?
Day one measures instead of guessing, under a fixed rubric, and the remaining hours are allocated in proportion to the gaps before any studying begins. The allocation is deliberately not renegotiated midweek, because the area that feels worst on day three is usually the one that is moving.
Prepare, practise & reflect
One practical outcome each day. Spend longer where you need it.
0 / 7 done01Local setup and the first chat server
- Set up the environment you will interview in: a fresh project in your strongest language, telnet or netcat installed, and a localhost port your firewall allows. Time how long it takes to go from a blank project to a running listener.
- Build the reported baseline: a multi-client TCP chat server that sends each message to every other client and does not echo it to the sender.
- Test with three terminal clients, then kill one mid-session and fix whatever breaks, such as a broken pipe or a client set that changes during iteration.
Deliverable: A server you can build from blank and demonstrate with three clients, plus a note of your setup time.
Practice prompt ↗Practice prompt ↗Practice prompt ↗Worked solution ↗02Extend the server the way the follow-ups do
- Add these one at a time: a nickname prompt on connect, a command that lists online users, join and leave notices, and clean shutdown.
- Rebuild the same server from blank with the other concurrency model (asyncio if you used threads, or the reverse) and write down one trade-off between the two.
- Frame input on newlines so a message split across two reads, and two messages in one read, are both handled correctly.
- Read the bank's DTLS buffer processing and telnet-compatible chat items and list the framing edge cases they raise.
Deliverable: Two working versions of the extended server and a one-paragraph comparison of threads and asyncio.
Practice prompt ↗Practice prompt ↗03Distributed coordination: leader election with leases
- Implement the reported leader-follower cluster against a local etcd: nodes compete for a key held by a TTL lease, the leader keeps the lease alive, and followers watch for its loss.
- Make followers redirect requests to the current leader, then kill the leader and measure how long failover takes.
- Write your answer for the stale-leader case, where an old leader pauses past its TTL and then resumes, and compare it with the bank's Redis-lease variant.
Deliverable: A running three-node demo and a short failure table: event, what each node does, and how long recovery takes.
Practice prompt ↗Practice prompt ↗04System design: matchmaking and message storage
- Talk through the reported matchmaking design aloud, starting from requirements: skill tiers, latency limits, wait time, and what you relax as players wait longer.
- Design message storage for a chat workload on ScyllaDB or PostgreSQL: partition key, ordering key, indexes, and the queries each choice makes expensive.
- Work the 'Page a materialized home timeline with a stable cursor' exercise, then apply its keyset-cursor rule to paging through a channel's message history.
Deliverable: Two one-page design sketches, each with a requirement list, a data model and three trade-offs.
Practice prompt ↗Practice prompt ↗Worked solution ↗05Incident troubleshooting
- Run the reported CPU-spike-after-deployment prompt aloud: what changed, which metrics and logs you ask for, how you bound the impact, the mitigation, and the root cause.
- Do the same for dropped socket connections during a connection burst, telling network saturation, thread-pool exhaustion and database lock contention apart by the signal each one leaves.
- Review C++ struct padding, alignment, and what breaks ABI compatibility when a client library changes, for the reported fundamentals question.
- Answer the 'Own the outage where one fanout starved every other author' drill using an incident of your own.
Deliverable: A one-page incident checklist and two recorded walk-throughs that follow it.
Practice prompt ↗Practice prompt ↗06Event data and applied product engineering
- Implement sessionization from an event stream: group each user's events into sessions split by a 30-minute gap, then compute per-channel engagement.
- Solve the 'Flag actors exceeding a rate ceiling in any sliding window' drill and work the 'Make the like write idempotent and the counter conditional' SQL exercise.
- If your target team works on clients, build a React message reaction bar with live counts, or a Snake game with a tick loop, keyboard input and collision checks, in your local IDE.
Deliverable: Working sessionization code with a test for a gap exactly at the boundary, plus one finished SQL or UI exercise.
Practice prompt ↗Practice prompt ↗07Retrospective, behavioral answers and a full mock
- Write your project retrospective as a timeline of decisions, with rejected options, one failure and one measured result.
- Answer the disagreement, deadline trade-off and explaining-to-non-technical-partners prompts aloud and record them.
- Run a mock of the technical screen: build the chat server from blank while a partner adds follow-up requirements live.
Deliverable: A one-page retrospective and a recorded mock, with notes on where you stalled.
Practice prompt ↗Practice prompt ↗Worked solution ↗Expand any day for tasks and deliverables. Your progress is saved on this device.
Candidates report that the virtual onsite includes a project retrospective and a values-alignment block, and the hiring manager call covers your background. Prepare one project you led in depth: the architecture choices, the trade-offs, what failed and what you learned. Follow-ups can go into missteps, edge cases and friction with other teams. Answer with specific decisions and measurable outcomes, not team-level summaries.
Tell me about a time when you were building a feature and had to make …
Tell me about a time when you were building a feature and had to make critical technical trade-offs under tight deadline pressure.
Approach
- Close with what you would do differently, concretely.
- Name the disagreement and how you resolved it with evidence.
- State the situation in two sentences and spend the rest on the reasoning.
Follow-up
- How did you know your change caused the improvement?
- What would you do differently if you ran that again?
Describe a situation where you had a significant technical disagreemen…
Describe a situation where you had a significant technical disagreement with your manager or team members, and explain how you arrived at a resolution.
Approach
- Pick a story where you made the decision, not one where you watched it.
- Name the disagreement and how you resolved it with evidence.
- Close with what you would do differently, concretely.
Follow-up
- What did you decide not to do, and why?
- What would you do differently if you ran that again?
Own the outage where one fanout starved every other author
Every author's timeline writes share one fanout queue. A publish by an account with roughly 12 million followers enqueued its entire follower fan, and for 41 minutes items from ordinary authors stopped reaching feeds while the backlog drained. Nothing errored: publishes returned 200, the read path was healthy, and error-rate dashboards stayed flat. Take the on-call role. Describe an incident you owned with a comparable silent blast radius: how it was detected, how you bounded who was affected, what you stopped first, and the one metric that sized the damage. Include what you got wrong during the response.
Approach
- Open with the invariant that broke, stated in a measurable form: a published item is materialized into follower timelines within N seconds at p99. The symptom (feeds look stale) tells a listener nothing countable; the invariant names both the damage and the metric.
- Explain why nothing errored, because that is the interesting part. An at-least-once queue degrades by lag, not by failure, so the detector has to be the age of the oldest unprocessed publish event per partition. Queue depth alone hides this case: depth is small when one task is enormous.
- Bound the population with two numbers you can derive, not an adjective. Publishes enqueued behind the stalled fan is a count from the queue; readers affected is the sum of account.follower_count over those authors. Say which one you actually computed during the incident and which you reconstructed after.
- Separate mitigation from fix and say which came first. Mitigation is to stop paying the cost now: flip the offending author to pull mode or move that fan to an isolated partition so small fanouts drain. State its immediate cost, which is a read path that must merge pushed and pulled items mid-incident. The threshold and per-size partitioning are the fix and are not an incident-window change.
- Say what redelivery did while you drained. Because a timeline write is an upsert on (owner_id, content_id), replayed events rewrote the same slots and the recovery was re-runnable; if the write had been an append, draining would have doubled entries in every timeline it touched.
- Name one thing you got wrong inside the response window, such as a mitigation that made the backlog worse or time spent on the wrong hypothesis. Interviewers weight this heavily because it is the part candidates rehearse away.
Follow-up
- Your mitigation flipped one author to pull mode. What must the feed read path do differently for viewers who follow that author, and how do you avoid serving them the item twice while already-pushed rows still exist?
- How would you have detected this in five minutes instead of 41, and what would that detector cost in false pages per week?
- The queue drained but some viewers were still missing items. Where do you look, and what exactly do you rebuild?
- 01
Walk through a complex technical project you led from inception to delivery, detailing architectural choices, key trade-offs, failures, and lessons learned.
- 02
Describe a situation where you had a significant technical disagreement with your manager or team members, and explain how you arrived at a resolution.
- 03
Tell me about a time when you were building a feature and had to make critical technical trade-offs under tight deadline pressure.
- 04
How do you communicate complex architectural decisions and technical trade-offs to non-technical cross-functional partners?
- 05
Walk through your background and the project you are most proud of.
- 06
Explain your database experience and how you approach debugging a production problem.
Is this an official Discord interview guide?
No. It is PracHub's own research and practice material for the Software Engineer role at Discord. The rounds and questions reflect what candidates have reported, not a process Discord has published, and they change over time. Confirm the current format and scope with your recruiter.
PracHub interview research ↗Can I use my own IDE and documentation during the live coding interviews?
Candidates report that Discord's coding interviews run in your own local development environment while you share your screen, and that you may look up standard language documentation and library APIs. Confirm the exact rules with your recruiter. Set up the environment beforehand: a project that runs, a terminal client such as telnet or netcat, and localhost ports your firewall does not block.
PracHub interview research ↗How is the technical screen different from a typical algorithm screen?
The reported technical screen is a practical implementation session, lasting 60 to 75 minutes according to reports. It often involves building a working network application such as a multi-client socket chat server. Expect to get a minimal version running first and then add follow-up requirements such as nicknames, a list of online users and disconnect handling. Practise that build end to end instead of only reading about sockets.
PracHub interview research ↗Should I still practise classic algorithms?
Yes, but make them secondary. Candidates report that the technical screen focuses on practical building, not puzzles. The question bank still lists coding items such as KMP string matching, DFS backtracking over character mappings, trie-based top-k completions and DTLS buffer packing. Keep strings, tries, backtracking and sliding windows in your practice, and spend most of your hours on sockets, concurrency and design.
PracHub Software Engineer practice ↗How long does the process take from first screen to offer?
Candidates report about three to five weeks across four stages: recruiter screen, hiring manager call, technical screen and virtual onsite loop. The pace depends on scheduling and team alignment, so ask your recruiter for the expected timeline, especially if you have another process running.
PracHub interview research ↗What should I expect during the virtual onsite?
Candidates report four to five back-to-back interview blocks held over Discord calls, covering live coding, system design, incident troubleshooting, a project retrospective and values alignment. Team-specific loops can change individual topics, so ask which blocks your loop includes and prepare each one as a separate skill.
PracHub interview research ↗Are AI coding assistants allowed in the coding rounds?
Reports differ. Reports say using generative AI to write core logic is discouraged and often not allowed. The question bank also lists a reported prompt about demonstrating an AI-assisted coding workflow. Ask your recruiter about the policy for each round. Be ready to code without help, and also to explain how you review and test code an assistant produced.
PracHub Software Engineer practice ↗Sources & methodology 3 sources ↗
Official role evidence, timestamped platform data and clearly labeled preparation advice.
- 01PracHub interview research ↗
PracHub editorial research into this company and role, maintained with this guide. Candidate-reported, not an employer publication.
platform · Accessed 2026-09-24 - 02PracHub Software Engineer practice ↗
Cross-company practice questions for this role.
platform · Accessed 2026-09-24 - 03PracHub interview preparation framework ↗
The framework the preparation plan follows.
platform · Accessed 2026-09-24