All topics
Functionsintermediate

Recursion and Stack Depth

Writing functions that call themselves to solve problems by breaking them into smaller subproblems, and the call-stack limits that come with it.

Recursion is a technique where a function solves a problem by calling itself on a smaller version of the same problem, continuing until it reaches a base case simple enough to answer directly without further recursion. It's a staple of technical interviews both because certain problems (tree traversal, divide-and-conquer algorithms) are naturally recursive, and because it tests whether you understand the call stack and its limits.

Recursion is like a set of Russian nesting dolls: each doll (call) contains a smaller version of the same problem, and you only start putting them back together (returning) once you hit the smallest, solid doll (the base case) that can't be opened further.

Key Concepts

1
Every recursive call pushes a new frame onto the call stack, holding that invocation's local variables and the point to return to once it completes. The recursion only terminates because of the base case — a condition checked at the start of the function that returns a direct answer without recursing further; without one, or with a base case that's never reached due to a bug, the function recurses forever (or until it crashes) since nothing tells it to stop.
2
Because each call consumes stack space, deeply recursive functions can exhaust the call stack, throwing a RangeError: Maximum call stack size exceeded — a real, common failure mode for recursive solutions applied to large inputs (like recursing over a 100,000-element array). Some languages solve this with tail-call optimization, where the engine reuses the current stack frame for a recursive call that's the very last operation in the function, turning recursion into loop-like constant stack usage — the ECMAScript spec actually defines proper tail calls, but in practice most JavaScript engines, including V8 (used in Chrome and Node), never implemented it, so relying on tail-call optimization in real-world JS is unsafe.
RangeError: Maximum call stack size exceeded
3
Given this, an iterative approach (using a loop, possibly with an explicit stack data structure to mimic the call stack manually) is usually the safer choice in JavaScript for problems where the recursion depth could be large or unbounded, while natural recursion remains perfectly fine, and often more readable, for problems with guaranteed shallow depth like tree structures of reasonable size.