DEV Community

Cover image for Practice Backend Incident Interviews With a 70-Line Node.js Drill
Karuha
Karuha

Posted on • Originally published at aceround.app

Practice Backend Incident Interviews With a 70-Line Node.js Drill

Backend incident questions are not trivia. They test whether you can diagnose safely under uncertainty, explain trade-offs out loud, and avoid making the outage worse. This tutorial gives you a small Node.js drill that randomizes production-style scenarios, asks the five questions interviewers care about, and scores whether your answer is evidence-led.

If you are preparing for a backend, platform, SRE-adjacent, or senior full-stack interview, run this drill until your answers stop sounding like a list of tools and start sounding like an operator thinking clearly.

Why incident questions are different from normal backend trivia

A normal backend question has a clean target:

  • What does idempotency mean?
  • When would you use a queue?
  • How does a database index work?
  • What is the difference between 401 and 403?

An incident question is messier:

"Your API latency jumped from 180ms to 4.8s fifteen minutes after a deploy. Error rate is flat. Database CPU is 96%. Walk me through the first minute."

The interviewer is not only checking whether you know databases, caches, traces, queues, and rollbacks. They are checking your operating model:

  • Do you trust evidence before guessing?
  • Can you scope blast radius quickly?
  • Can you hold two hypotheses without overcommitting?
  • Can you choose a safe test instead of poking production randomly?
  • Can you mitigate before root cause is fully known?

That is why reading incident postmortems helps, but it is not enough. In an interview, you need retrieval plus narration. You have to say the process clearly while someone is evaluating you.

Five-step backend incident interview loop

The five-step answer shape

Use this loop when the prompt sounds like production is on fire:

Step What the interviewer wants Bad answer pattern Strong answer pattern
Detect Which signal you trust first "I check logs" "I start with service metrics, then sample traces, because one log line can lie"
Scope How wide the issue is "Maybe the DB is slow" "Compare region, endpoint, customer tier, deploy window, and dependency health"
Hypothesize Whether you can reason under uncertainty "It is probably Redis" "If cache hit rate dropped, I expect DB QPS to rise; I would disprove it by comparing pre/post deploy cache metrics"
Test Fastest safe check "I run some queries" "Sample slow traces and inspect one hot query plan before changing anything"
Mitigate How you reduce harm "Fix the bug" "Rollback, disable the flag, throttle retries, or shed non-critical traffic while communicating status"

The drill below forces you through those five steps. It is intentionally small. You can paste it into a file, run it, and practice speaking your answers out loud.

Build the Node.js incident drill

Create incident-drill.mjs:

import { createInterface } from 'node:readline/promises';
import { stdin as input, stdout as output } from 'node:process';

const scenarios = [
  {
    title: 'API p95 latency jumped from 180ms to 4.8s after deploy',
    context: 'Checkout service, Node.js API, Postgres, Redis cache, 15 minutes after a release.',
    clues: ['p95 up, error rate flat', 'DB CPU 96%', 'cache hit rate dropped from 82% to 23%'],
  },
  {
    title: 'Background jobs are delayed by 40 minutes',
    context: 'Queue workers process invoices. Web traffic is normal, but customers report missing receipts.',
    clues: ['queue depth growing', 'workers restarted twice', 'one downstream API returns many 429s'],
  },
  {
    title: 'Error rate is 12% in one region only',
    context: 'Multi-region backend behind a global load balancer. The incident started without a deploy.',
    clues: ['us-east affected', 'health checks flapping', 'database replicas lagging 90 seconds'],
  },
];

const steps = [
  { name: 'Detect', prompt: 'What signal do you trust first, and why?', keywords: ['metric', 'log', 'trace', 'dashboard', 'alert'] },
  { name: 'Scope', prompt: 'How do you narrow blast radius in 60 seconds?', keywords: ['region', 'endpoint', 'customer', 'deploy', 'dependency'] },
  { name: 'Hypothesize', prompt: 'Give two likely causes and one thing that would disprove each.', keywords: ['because', 'if', 'disprove', 'compare', 'baseline'] },
  { name: 'Test', prompt: 'What is the fastest safe check you would run?', keywords: ['query', 'rollback', 'sample', 'feature flag', 'canary'] },
  { name: 'Mitigate', prompt: 'What do you do before you know the root cause?', keywords: ['rollback', 'throttle', 'disable', 'scale', 'communicate'] },
];

const demoAnswers = [
  'I trust metrics first, then dashboard traces, because one log line may lie.',
  'Compare region, endpoint, customer tier, deploy time, and dependency health.',
  'If cache hit rate fell, compare to baseline; if DB changed, disprove with query plans.',
  'Sample slow traces, inspect the hot query, and consider a canary rollback.',
  'Rollback or disable the feature flag, throttle retries, and communicate status.',
];

const demoMode = process.argv.includes('--demo');
const pick = (items) => items[Math.floor(Math.random() * items.length)];
const rl = demoMode ? null : createInterface({ input, output });
const scenario = pick(scenarios);
let score = 0;

async function ask(step, index) {
  const question = `\n${step.name}: ${step.prompt}\n> `;
  if (demoMode) {
    const answer = demoAnswers[index];
    console.log(question + answer);
    return answer.toLowerCase();
  }
  return (await rl.question(question)).toLowerCase();
}

console.log('\nBackend incident interview drill\n');
console.log('Scenario:', scenario.title);
console.log('Context:', scenario.context);
console.log('Clues:');
for (const clue of scenario.clues) console.log('-', clue);

for (const [index, step] of steps.entries()) {
  const answer = await ask(step, index);
  const hits = step.keywords.filter((word) => answer.includes(word));
  score += Math.min(hits.length, 2);
  console.log(hits.length ? `Signals heard: ${hits.join(', ')}` : 'Missing concrete signal. Try again with evidence.');
}

console.log(`\nScore: ${score}/10`);
console.log(score >= 8 ? 'Strong: structured, evidence-led, and safe.' : 'Repeat once. Add metrics, blast radius, and a reversible mitigation.');
rl?.close();
Enter fullscreen mode Exit fullscreen mode

Run the demo mode first:

node incident-drill.mjs --demo
Enter fullscreen mode Exit fullscreen mode

Then run it interactively:

node incident-drill.mjs
Enter fullscreen mode Exit fullscreen mode

The score is deliberately crude. It is not trying to grade your engineering ability. It is checking whether your spoken answer contains the nouns interviewers listen for: metrics, traces, regions, endpoints, dependencies, baselines, queries, rollbacks, throttling, and communication.

How to use this in a 30-minute practice session

Do not silently type perfect answers. That misses the point.

Use this format:

  1. Run the script and read the scenario out loud.
  2. Give yourself 60 seconds for the Detect and Scope answers.
  3. Give yourself 90 seconds for Hypothesize and Test.
  4. Give yourself 45 seconds for Mitigate.
  5. After the score, rewrite only the weakest answer and say it again.

A good session is not one where you sound polished. A good session is one where your second attempt is more specific than your first.

For example, this is vague:

"I would check the logs and maybe rollback if something looks bad."

This is stronger:

"Because the latency spike started after a deploy and errors are flat, I would first compare p50, p95, and p99 latency by endpoint and region. If one endpoint regressed, I would sample traces for that route and compare DB query count before and after the release. If the new code path is obvious, I would roll back or disable the feature flag before digging into root cause."

Notice the difference: the second answer names evidence, blast radius, a falsifiable hypothesis, a safe test, and a reversible mitigation.

Add your own scenarios

The easiest way to make the drill useful is to add scenarios from your own work history. Keep them anonymous and remove employer-specific details.

Good scenario inputs:

  • "Kafka consumer lag grows for one topic after a schema change"
  • "Payment API is idempotent in code but duplicate charges still appear"
  • "Search endpoint is fast for small tenants and slow for enterprise tenants"
  • "A cron job succeeds but downstream data is missing"
  • "A memory leak appears only after traffic doubles"

Try to include three clues per scenario: one metric, one timing clue, and one dependency clue. That gives you enough evidence to reason without turning the exercise into a mystery novel.

Where AI fits without turning the prep into a shortcut

A terminal script is useful because it makes you practice. A human mock interviewer is better because they interrupt, ask follow-ups, and notice when you are hand-waving. AI sits in the middle: good enough to create repetitions, ask follow-ups, and keep you honest when you drift into vague language.

I work on aceround.app — AI interview assistant, so I obviously care about this category. But the rule I use for my own prep is simple: use AI to create pressure and feedback, not to replace your judgment. If the tool gives you an answer you could not defend, it is not preparation. It is debt.

FAQ

Should I mention rollback immediately?

Mention it as an option, not a reflex. A strong answer says when rollback is safe: recent deploy, clear regression window, reversible change, no dangerous migration, and no evidence that rollback would worsen data consistency.

Should I always start with logs?

No. Logs are useful, but interviews reward signal hierarchy. Start with high-level metrics and user impact, then use traces and logs to explain why the metric moved.

What if I have never handled a real production incident?

Use open-source postmortems and your own side projects. The interview skill is not pretending you were on-call for a massive system. It is showing disciplined reasoning: evidence, scope, hypothesis, test, mitigation.

Is the keyword score too easy to game?

Yes, and that is fine. The score is a practice constraint, not an evaluation system. Once you consistently score 8 or above, stop caring about the number and focus on whether your answer sounds natural under time pressure.

Final take

Backend incident interviews are stressful because they compress production judgment into a few minutes. You do not need a memorized answer for every outage. You need a repeatable loop: detect, scope, hypothesize, test, mitigate.

Run the drill five times. Record one answer. Listen for vague phrases like "check things" or "look into the database." Replace them with specific signals and safe actions. That one habit will improve more backend interview answers than another night of passive reading.


Disclosure: I used AI assistance to draft and edit this article, then manually reviewed the technical flow, ran the Node.js script in --demo mode, checked the generated images, and rewrote the promotional section to keep the article primarily instructional.

Top comments (0)