Design a Coding Contest Platform like LeetCode: System Design Interview (2026)

Anand Rochlani · July 31, 2026 · 9 min read

Design a Coding Contest Platform like LeetCode: System Design Interview (2026)

Learn LeetCode system design for interviews: contest traffic spikes, sandboxed judge queues, and Redis leaderboards. Master the answer that impresses.

LeetCode System Design: Why This Question Keeps Showing Up

You are asked to design a coding contest platform like LeetCode: users submit code, the platform runs it against hidden test cases, and a live leaderboard ranks everyone in real time. It sounds simple until you remember that a weekly contest starts for everyone at the exact same second. That one detail is why interviewers love this question.

What Happens When a Contest Starts? The Thundering Herd Problem

Most systems see traffic build up gradually. A contest platform is different: for six days the site is quiet, and then at 8:00:00 PM on Sunday, 100,000 people load the problem page in the same second.

Think of an exam hall with 100,000 students. Nobody touches the paper until the bell rings, and then everyone flips the page at once. This spike pattern is called a thundering herd, and it hits three places at once:

  • The problem page: everyone requests the same 4 problem statements simultaneously.
  • The submission endpoint: within minutes, tens of thousands of solutions arrive for judging.
  • The leaderboard: everyone refreshes it obsessively to see their rank.

The problem page is the easy win. Problem statements are identical for every user and never change during the contest, so cache them aggressively at the CDN and in memory. Not one of those 100,000 reads should touch your database. If caching is fuzzy for you, read how caching strategies improve performance first, because this design leans on it everywhere.

How Does the Submission Flow Work?

Here is the core insight of the whole design: judging code is slow, but accepting a submission is fast. Running someone's solution against 50 test cases can take several seconds. If your web server does that work while the user waits on an open HTTP connection, a few thousand submissions will exhaust every thread you have and the site goes down mid-contest.

So we split the two. The submission flow looks like this:

  1. User submits code. The API server validates the basics (contest is live, user is registered, code size is within limits).
  2. The server stores the submission in the database with status PENDING and pushes a message onto a message queue (Kafka or SQS). The message is tiny: submission ID, problem ID, language.
  3. The server immediately responds with "submission received." Total time: a few milliseconds. The user's browser now polls for the result or listens on a WebSocket.
  4. A judge worker pulls the message from the queue, fetches the code, runs it against the test cases, and writes back the verdict: Accepted, Wrong Answer, Time Limit Exceeded, or Runtime Error.
  5. The result flows back to the user and, if accepted, into the leaderboard.

This is asynchronous processing with a queue as a buffer. When 50,000 submissions arrive in five minutes, the queue simply gets longer. Nothing crashes. Users wait 20 seconds instead of 5 for a verdict during the peak, and that is an acceptable trade.

Why Do Judge Workers Need a Sandbox?

Here is the part beginners miss: you are running untrusted code from strangers on your own servers. Someone will submit code that reads environment variables, opens network connections, forks thousands of processes, or fills the disk. Some of it is malicious, most is just buggy, and both can take a machine down.

So every judge worker runs submissions inside a sandbox, an isolated box with strict limits:

  • No network access. The submitted code cannot call the internet or your internal services.
  • CPU and memory limits. A solution gets, say, 2 seconds of CPU and 256 MB of memory. Exceed either and the run is killed with Time Limit Exceeded or Memory Limit Exceeded.
  • Read-only filesystem except for a small scratch space that is wiped after every run.
  • Process limits so a fork bomb dies instantly instead of taking the worker with it.

In practice this means a locked-down container (Docker with seccomp profiles, or lighter isolation like gVisor). In the interview, saying "each submission runs in an isolated sandbox with CPU, memory, time, and network limits, and the sandbox is destroyed after the run" is exactly the right level of detail.

How Do You Scale the Judges? Horizontal Scaling

The queue solved the spike, but a queue that only grows is just a slow-motion failure. You need enough judge workers to drain it at a reasonable rate.

The beautiful property of this design is that judge workers are stateless. Each one pulls a message, does its work, writes a result, and pulls the next. No worker depends on any other worker. That makes them perfect for horizontal scaling: need more judging capacity, add more machines. It is the same scale-out principle covered in the beginner's guide to throughput, applied to background workers instead of web servers.

Even better, you can autoscale on queue depth. During the week, run 10 workers. When the contest starts and queue length crosses a threshold, spin up to 500 workers, then scale back down an hour later. Do the capacity math out loud in the interview: at roughly 5 seconds per judgment, one worker handles 12 per minute, so 500 workers handle 6,000 per minute, which comfortably drains a 50,000-submission burst.

How Do You Build a Real-Time Leaderboard? Redis Sorted Sets

Now the leaderboard. Ranking 100,000 users with ORDER BY score DESC on every page load would melt a SQL database. The standard answer is a Redis sorted set.

A sorted set stores members (user IDs) with a numeric score and keeps them ordered at all times. Every operation you need is built in and fast:

  • ZADD updates a user's score when a solution is accepted, in O(log N).
  • ZREVRANGE fetches the top 100 for the leaderboard page, in milliseconds.
  • ZREVRANK tells any user their exact current rank instantly.

Because everything lives in memory, the leaderboard handles enormous read traffic without touching the primary database. You can also cache the rendered top-100 page for 2 or 3 seconds, since nobody can tell the difference and it cuts Redis load dramatically during refresh storms.

How do you handle ranking ties?

Two users solve all four problems. Who ranks higher? Contest rules say: whoever finished earlier, with penalty minutes added for wrong submissions. A sorted set holds one score per member, so you encode both facts into a single number, a composite score: score = (problems_solved × a large constant) − penalty_seconds. Problems solved dominates, and among equals, lower penalty time wins.

What about consistency?

Redis is fast but it is a cache-grade store, and the leaderboard is being updated by hundreds of workers concurrently. The rule is: the database is the source of truth, Redis is the live view. Every accepted submission is durably recorded in the database first; the ZADD is a derived update. If Redis crashes mid-contest, you rebuild the sorted set by replaying accepted submissions from the database. And the final official ranking after the contest is computed once, carefully, from the database, not read off Redis. Live scores can be a few seconds stale and nobody is harmed; final standings must be exact. Saying that sentence in an interview shows real judgment about which parts of a system need strong consistency.

Plagiarism Detection: The Async Batch Job

Contest platforms compare every accepted solution against every other to catch cheaters. That is an expensive pairwise computation, and here is the key observation: nothing about it is urgent. Cheaters need to be caught before prizes go out, not in real time.

So plagiarism checking runs as an asynchronous batch job after the contest ends. A scheduled pipeline pulls all accepted submissions, normalizes the code (strip comments, whitespace, and variable names), computes similarity fingerprints, and flags suspicious pairs for human review. It runs on cheap spare capacity at 2 AM and touches nothing in the serving path.

This is a pattern interviewers genuinely reward: separating the real-time path from the batch path. Judging is near-real-time, the leaderboard is real-time, plagiarism is batch. Sorting requirements into those buckets is the mark of a mature designer.

Want to master this with video lessons and real case studies? This topic is covered in depth in my Udemy course System Design Fundamentals for Interviews — 5.5 hours, rated 4.8★, built from real interview questions.

What Breaks at 100,000 Concurrent Users?

A strong interview answer names the failure points before the interviewer does. Walk through them:

  • The submission API becomes the front-line bottleneck. One server cannot accept 100k connections, so you run many stateless API servers behind a load balancer that distributes traffic across servers, and you rate-limit per user so one script kiddie cannot spam submissions.
  • The database write path gets hammered by submission inserts and status updates. Batch the status writes, keep the hot contest tables lean, and push every read you possibly can to caches and replicas.
  • Result delivery hurts if 100k browsers poll for verdicts every second. That is 100k RPS of mostly useless "still pending" responses. Use WebSockets or long polling to push the verdict when it is ready, or at minimum poll with backoff.
  • The judge queue backs up if autoscaling is too slow. Pre-warm the worker fleet a few minutes before the contest starts; you know the exact second the herd arrives, which is a luxury most systems never get.
  • Leaderboard refresh storms can overwhelm even Redis. The 2-second cached snapshot of the top 100 absorbs almost all of it.

How to Talk About This in an Interview

Here is a 30-second answer you can memorize and deliver before diving into details:

"A contest platform has a unique spiky load: everyone arrives the second the contest starts. I would keep the submission path asynchronous: the API accepts a submission, persists it, drops a message on a queue, and returns immediately. Stateless sandboxed judge workers pull from the queue, run the code with strict CPU, memory, and network limits, and write back verdicts, and I autoscale the workers on queue depth. The live leaderboard is a Redis sorted set with a composite score that encodes tiebreaks, rebuilt from the database if needed, since the database stays the source of truth. Plagiarism detection runs as an offline batch job after the contest. Problem statements are static, so they are served entirely from CDN and cache."

Then let the interviewer pick a thread: usually the sandbox, the tiebreak encoding, or the consistency story, and you have a prepared answer for each.

Key Takeaways

  • Contest traffic is a thundering herd: design for the spike at contest start, not for average load.
  • Decouple accepting submissions from judging them with a message queue; judging is asynchronous.
  • Judge workers run untrusted code in sandboxes with CPU, memory, time, and network limits, and scale horizontally on queue depth.
  • The live leaderboard is a Redis sorted set with a composite score for tiebreaks; the database remains the source of truth for final rankings.
  • Plagiarism detection is a batch job: always separate real-time paths from batch paths.

Next Steps

You have now designed a system built around one giant synchronized spike. The next case study flips the problem: Facebook News Feed, where the challenge is not one spike but billions of personalized reads all day long, and the classic fan-out-on-write versus fan-out-on-read decision. Read it next: Design Facebook News Feed: A System Design Interview Guide.