Skip to content

Boarding pass · Node.js Advanced

Node.js · Advanced interview

An AI mock interview for senior Node.js engineers. Reason about libuv internals, scaling and diagnosing the event loop, resilient service architecture, graceful shutdown, and production reliability and security.

20–30 minEstimated6 questionsTailored live12 model answersTo study
  • Voice interview
  • Live feedback
  • Browser-only
  • No installation required

Your report · sample

AI Readiness Score

/100
Content score English score

Finish the mock and get this report — scored on content and English, with concrete tips and a model answer for every question, plus a study plan.

Your flight path

Five steps to interview-ready.

From a quick warm-up to a personalised study plan — here's the whole loop, and what you get at each gate.

  1. Step 01

    Preparation

    Skim the topics and warm up — you're briefed before takeoff.

  2. Step 02

    AI Interview

    A realistic AI interviewer asks tailored questions — answer by voice or text.

  3. Step 03

    Instant Score

    Finish and get a 0–100 readiness score across content and English.

  4. Step 04

    AI Feedback

    Concrete tips and a rewritten model answer for every response.

  5. Step 05

    Study Plan

    A personalised plan targets your weakest areas — so the next run scores higher.

Preview the AI demo

See one answer scored, end to end.

The whole loop on sample data — question, your answer, instant feedback and a study plan. Hover to pause.

aevrofy.com/session · live demoPlaying

Interviewer · Question 1

“Tell me about yourself.”

Who it's for

  • Senior backend engineers
  • Engineers who own Node services in production
  • Anyone targeting senior/lead backend roles
  • Devs who diagnose and tune Node at scale

What you'll practice

  • Explaining libuv and the thread pool
  • Scaling across cores and processes
  • Diagnosing event-loop lag and leaks
  • Designing for graceful shutdown and resilience

Topics covered

What this level expects.

Internals

  • libuv & thread pool
  • Module resolution & caching
  • V8 & GC

Scaling

  • Cluster vs workers
  • Statelessness
  • Load shedding

Reliability

  • Graceful shutdown
  • Uncaught errors
  • Backpressure in prod

Security

  • Input & injection
  • Secrets
  • Dependency risk

Practice questions

12 questions, with model answers.

Read them, then run the live mock to answer out loud and get scored. Tap any question to reveal a model answer.

01How does libuv's thread pool relate to the single-threaded event loop?

Your JS callbacks run on one thread, but certain operations can't be done asynchronously by the OS — filesystem work, DNS lookups (getaddrinfo), and crypto like pbkdf2 — so libuv runs them on a small thread pool (default size 4, set by UV_THREADPOOL_SIZE) and posts the results back to the event loop. Network I/O, by contrast, uses the OS's async facilities (epoll/kqueue/IOCP), not the pool. Saturating the pool with heavy crypto or fs work serializes those operations even though the loop looks idle.

02How does Node's module resolution and require caching work?

For CommonJS, require resolves a specifier through core modules, then node_modules lookups walking up directories, applying extensions and package.json "main"/"exports". The first require executes the module and caches module.exports in require.cache keyed by resolved path, so later requires return the same instance — which is why modules behave like singletons. Mutating that cache or relying on it for state is a common source of subtle bugs.

03What should you know about V8 garbage collection when running Node at scale?

V8 uses a generational GC: short-lived objects live in a small 'new space' collected cheaply and often; survivors are promoted to 'old space' collected by mark-sweep/compact, which can pause. Large heaps mean longer pauses, and the heap is capped (--max-old-space-size). At scale you keep allocations low and short-lived, avoid retaining big graphs, and watch for GC pauses showing up as latency spikes.

04How do you scale a Node service across CPU cores, and what changes in your code?

Run one process per core — via the cluster module, a process manager like PM2, or (more commonly now) multiple container replicas behind a load balancer. The key constraint is that processes don't share memory, so your app must be stateless: no in-process sessions or caches you rely on. Shared state moves to Redis or a database, and sticky sessions or a shared store handle anything connection-bound like WebSockets.

05How do you protect a Node service from being overwhelmed by load?

Apply backpressure and load shedding: set request timeouts and body-size limits, rate-limit per client, bound concurrency to downstream dependencies (connection pools, queues), and shed or queue excess work instead of accepting unbounded requests. Health checks plus a circuit breaker around flaky dependencies stop a slow dependency from cascading into a full outage.

06How would you diagnose event-loop lag in production?

Measure it directly — monitor.eventLoopDelay (perf_hooks) or a histogram exported to your metrics, and alert when p99 delay rises. To find the cause, profile with --prof or the inspector, capture flame graphs (0x/clinic flame), and look for synchronous hotspots: JSON.stringify of huge payloads, sync crypto/fs, regex backtracking, or large loops. The fix is to move that work off the main thread or chunk it.

07How do you implement graceful shutdown of a Node service?

On SIGTERM, stop accepting new work (server.close()), let in-flight requests finish within a timeout, drain queues, close database and Redis connections, then exit. You also fail health checks first so the load balancer stops routing to the instance. A hard timeout forces exit if something hangs. This is what makes rolling deploys zero-downtime.

process.on("SIGTERM", async () => {
  server.close();
  await Promise.allSettled([db.end(), redis.quit()]);
  process.exit(0);
});
08How should uncaughtException and unhandledRejection be handled?

Treat an uncaughtException as the process being in an unknown, possibly corrupt state: log it, run minimal cleanup, and exit so a supervisor restarts a fresh process — don't try to resume. unhandledRejection should be logged and surfaced (and in newer Node it can also crash by default); the real fix is to attach a .catch or await with try/catch everywhere. Relying on these handlers to keep limping along is a reliability anti-pattern.

09How does backpressure show up in a real production system, beyond a single stream?

It's the same idea at system scale: if you consume from a queue or socket faster than you can process or persist, memory and latency grow until something falls over. You bound it with concurrency limits on consumers, prefetch/ack windows on the message broker, connection-pool limits to the database, and pausing intake when downstream is slow. The principle is to make the slowest stage set the pace, not the fastest.

10What are the most important security practices for a Node API?

Validate and sanitize all input against schemas; use parameterized queries or an ORM to prevent injection; set security headers (helmet) and strict CORS; rate-limit and add authn/authz on every route; keep secrets in env/secret managers, never in code; and run least-privilege. Also audit dependencies (npm audit, lockfiles, Dependabot) since most real-world Node vulnerabilities come through the supply chain.

11Why are third-party dependencies a particular risk in Node, and how do you manage it?

Node projects pull in large, deep dependency trees, so a single compromised or malicious transitive package can run code in your build or runtime. Manage it by pinning with a committed lockfile, auditing regularly, minimizing dependencies, vetting popular/maintained packages, using npm ci in CI, and considering provenance and tools like socket/Snyk. Treat adding a dependency as a security decision, not just a convenience.

12When would you reach for worker_threads, child_process, or a separate service?

worker_threads for CPU-bound work you want parallelized inside the process with shared memory (e.g. image/crypto processing). child_process/spawn to run external programs or isolate crashy work in its own process. A separate service when the work has a different scaling profile, lifecycle, or language, or needs independent deployment. The decision is about isolation, scaling, and failure boundaries, not just performance.

Preparation tips

Walk in ready.

  • Be able to explain what actually runs on the thread pool
  • Have a concrete event-loop-lag investigation story
  • Know the steps of a zero-downtime deploy
  • Treat uncaughtException as fatal — drain and exit

Ready for the real thing?

Run a 6-question Node.js mock interview, answer out loud, and get a readiness score with tips and model answers.

More advanced interviews

Aevrofy · Node.js advanced interview prep