← Back to list

System Design Challenge: How Would You Design LeetCode?

A mock-interview style breakdown of designing coding problems, code execution, queues, runtime workers, caching, and live contest…

Neha Gupta in Dev Simplified · 2026-06-24 06:31 · 13 claps · 5.6 min read paywalled
#design-systems #leetcode #software-engineering #system-design-concepts #programming
Open on Medium ↗
Wiki topics: PRD · Product Design 💻 · Programming 👗 · Fashion

System Design Challenge: How Would You Design LeetCode?

A mock-interview style breakdown of designing coding problems, code execution, queues, runtime workers, caching, and live contest leaderboards.

Thumbnail Image: System Design Challenge: How Would You Design LeetCode?

Thumbnail Image: System Design Challenge: How Would You Design LeetCode?

“Design LeetCode” sounds like a simple system design question.

At first, you may think:

Show problems. Let users write code. Run test cases. Return accepted or failed.

But an interviewer will not stop there.

The real discussion begins when they ask:

“Where will you run user-submitted code safely?”

That one question changes the whole design.

Because now we are not just designing a CRUD app. We are designing a platform that runs unknown code, handles contest traffic, updates live leaderboards, and still stays available when thousands of developers submit solutions at the same time.

Let’s walk through this like a real system design interview.

Interviewer: What are the core requirements?

Before jumping into architecture, I would first clarify the scope.

For a LeetCode-like platform, the main features can be:

  1. View a list of coding problems
  2. Open a problem and write code in any supported language
  3. Submit code and get feedback
  4. Support weekly or bi-weekly contests
  5. Show a live leaderboard during contests

And to keep the discussion focused, we can keep these out of scope:

  • authentication
  • user profiles
  • payments
  • premium subscriptions
  • detailed analytics

This helps because system design interviews are not about designing everything. They are about choosing the right scope and going deep where it matters.

Image: Requirements split into In Scope vs Out of Scope

Image: Requirements split into In Scope vs Out of Scope

Interviewer: How would users view problems?

This part is simple.

We need an API to fetch coding problems.

GET /problems?page=1&limit=100&difficulty=medium

Even if the platform has only 4,000–5,000 problems, pagination still makes sense. We do not want to load every problem on the first page.

A problem object may look like this:

const problem = {
  id: "two-sum",
  title: "Two Sum",
  difficulty: "easy",
  description: "...",
  constraints: "...",
  examples: [],
  supportedLanguages: ["javascript", "python", "cpp"]
};

For opening one specific problem:

GET /problems/:problemId?language=javascript

The language parameter is useful because each language may need a different starter template.

For example, JavaScript may show:

function twoSum(nums, target) {
  // write your code here
}

Python may show:

def twoSum(nums, target):
    pass

Small detail, but important.

The problem is the same. The coding environment changes based on language.

Interviewer: What happens when the user submits code?

This is where most beginner answers become weak.

A basic endpoint may look like this:

POST /problems/:problemId/submit

Request body:

{
  "code": "function twoSum(nums, target) { ... }",
  "language": "javascript"
}

At first, it feels natural to run this code directly on the API server.

Something like this:

app.post("/problems/:id/submit", async (req, res) => {
  const result = await runCode(req.body.code, req.body.language);
  res.json(result);
});

But this is a dangerous design.

Because user code can do anything.

  • It can run an infinite loop.
  • It can consume memory.
  • It can crash the server.
  • It can try to access files.
  • It can slow down other submissions.

So the API server should not execute code directly.

It should only accept the submission and push it for execution.

Interviewer: Then where should the code run?

A better flow is:

  1. User submits code
  2. API server creates a submission record
  3. API server pushes a job to a queue
  4. Runtime worker picks the job
  5. Worker runs code in an isolated environment
  6. Result is stored in the database
  7. User receives status

Code flow:

app.post("/problems/:id/submit", async (req, res) => {
  const submission = await db.submissions.create({
    problemId: req.params.id,
    userId: req.user.id,
    code: req.body.code,
    language: req.body.language,
    status: "queued",
    submittedAt: Date.now()
  });
   await queue.publish("code-submission", {
    submissionId: submission.id
  });
  res.json({
    submissionId: submission.id,
    status: "queued"
  });
});

This design is better because traffic spikes do not directly overload runtime machines.

The queue acts like a buffer.

During contests, this becomes very useful because many users submit code at almost the same time.

Interviewer: How do you safely execute unknown code?

There are a few options.

Image: Approach vs Benefit vs Problem

Image: Approach vs Benefit vs Problem

For a coding platform, container-based runtime workers are a practical choice.

We can have different worker pools for different languages:

const runtimeWorkers = {
  javascript: "node-worker",
  python: "python-worker",
  cpp: "cpp-worker"
};

Each worker should enforce limits:

const EXECUTION_TIMEOUT_MS = 5000;
const MEMORY_LIMIT_MB = 256;

A timeout is not optional.

Without it, this code can keep running forever:

while (true) {
  console.log("running");
}

So the worker must stop execution after a fixed time.

This is how platforms show errors like Time Limit Exceeded.

Interviewer: Do we need separate test cases for every language?

No.

This is a common misconception.

The test cases can be language-neutral.

For example:

{
  "input": [[2, 7, 11, 15], 9],
  "expectedOutput": [0, 1]
}

Then each runtime converts the input into the format needed by that language.

JavaScript wrapper:

const input = [[2, 7, 11, 15], 9];
const result = twoSum(...input);
console.log(JSON.stringify(result));

Python wrapper:

input_data = [[2, 7, 11, 15], 9]
result = twoSum(*input_data)
print(result)

Same test case. Different language wrapper.

That is the clean way to support multiple languages without duplicating test data.

Interviewer: How would you design the contest leaderboard?

Now the system gets more interesting.

During a contest, users are not only submitting code. They are also refreshing the leaderboard again and again.

A simple endpoint can be:

GET /contests/:contestId/leaderboard?page=1&limit=100

The naive design is to query the submissions database every few seconds.

const submissions = await db.submissions.find({
  contestId,
  status: "accepted"
});

This works for small traffic.

But during a large contest, this can put too much load on the database.

A better approach is to maintain the leaderboard in cache.

async function updateLeaderboard(contestId, userId, score) {
  await cache.zadd(`leaderboard:${contestId}`, score, userId);
}

Then reading top users becomes fast:

const leaders = await cache.zrevrange(
  `leaderboard:${contestId}`,
  0,
  99,
  "WITHSCORES"
);
  • The database remains the source of truth.
  • The cache makes leaderboard reads fast.

This is a good tradeoff because the leaderboard can tolerate slight delay, but the platform should not go down.

Interviewer: What should the submission schema look like?

A submission record should include enough data to support judging and leaderboard ranking.

const submission = {
  id: "sub_123",
  userId: "user_456",
  problemId: "two-sum",
  contestId: "contest_789",
  language: "javascript",
  status: "accepted",
  runtimeMs: 82,
  submittedAt: 1710000000000
};

For contest ranking, indexing by contestId is useful.

Why?

Because leaderboard queries usually ask:

“Give me all accepted submissions for this contest.”

They do not start with submission ID.

This is a small design decision, but it matters a lot when traffic increases.

Interviewer: How would you scale this system?

There are three important areas to scale.

1. API servers

API servers can be horizontally scaled behind a load balancer.

2. Runtime workers

Runtime workers can scale based on queue size.

If the queue grows, add more workers.

if (queue.pendingJobs > 10000) {
  scaleRuntimeWorkers("up");
}

3. Leaderboard reads

Leaderboard reads should mostly hit cache, not the database.

This keeps the database safe during contests.

The Key Insight

The hardest part of designing LeetCode is not storing problems.

It is safely running unknown code at scale.

The second hardest part is handling contest behavior.

During contests, users submit frequently, refresh leaderboards, and expect quick feedback. This creates sudden traffic spikes.

So the design depends heavily on:

  • queues
  • runtime isolation
  • caching
  • timeouts
  • horizontal scaling
  • good database indexes

Most of the architecture exists to protect the system from user code and traffic spikes.

Final Takeaways

A strong LeetCode system design answer should not stop at APIs.

You should discuss:

  • functional and non-functional requirements
  • problem listing APIs
  • code submission flow
  • queue-based execution
  • isolated runtime workers
  • language-specific wrappers
  • timeout and memory limits
  • submission schema
  • live leaderboard caching
  • contest-time scaling

The simplest version of LeetCode is a CRUD app.

The real version is a distributed system built around one difficult question:

How do you run unknown code safely, quickly, and at scale?

That is where the actual interview begins.

From Dev Simplified

  • 👏 Enjoyed the article? Don’t forget to leave a clap.
  • 💬 Have thoughts or questions? Share them in the comments.
  • ✍️ Want to write for Dev Simplified? Drop a personal note on any Dev Simplified story with your draft link.

메타데이터
post_id
61ae8875ee22
slug
system-design-challenge-how-would-you-design-leetcode-61ae8875ee22
url
https://medium.com/dev-simplified/system-design-challenge-how-would-you-design-leetcode-61ae8875ee22
canonical_url
https://medium.com/dev-simplified/system-design-challenge-how-would-you-design-leetcode-61ae8875ee22
author_url
https://medium.com/@techbynehagupta
status
ok
fetched_at
2026-06-27 09:04:44