DEV Community

Mohamed Idris
Mohamed Idris

Posted on

Recursion in 5 Minutes (with examples)

The one-line definition: a function that calls itself until it hits a stopping condition.

That's it. Everything else is just patterns.

An example: Russian dolls (matryoshka)

You open a Russian doll. Inside is a smaller doll. Open it → another smaller doll inside. Keep opening until you find the tiniest doll with nothing inside. Then you know the answer: "there were 5 dolls."

You could write that as a recipe:

openDoll(doll):
  if doll is empty inside:
    return 1                           the stopping condition
  else:
    return 1 + openDoll(inside doll)   the function calls itself
Enter fullscreen mode Exit fullscreen mode

Two ingredients every recursion needs:

  1. Base case — when to stop (if doll is empty).
  2. Recursive step — call yourself on a smaller version of the problem (openDoll(inside doll)).

If you forget the base case, you recurse forever and crash. That is the #1 recursion bug.

Concrete: countdown from 3

Easiest possible recursion in JavaScript:

function countdown(n) {
  if (n === 0) {                   // base case
    console.log("done!");
    return;
  }
  console.log(n);                  // do work
  countdown(n - 1);                // call itself with a smaller n
}

countdown(3);
Enter fullscreen mode Exit fullscreen mode

What gets printed:

3
2
1
done!
Enter fullscreen mode Exit fullscreen mode

Trace it yourself

Imagine the function is a sticky note. Every time it calls itself, you grab a NEW sticky note and start it. Old sticky notes wait, paused, until the new one finishes.

countdown(3) starts ────────────────────┐
   prints "3"                           │
   calls countdown(2) ─────────────┐    │  ← waiting
                                   │    │
       countdown(2) starts         │    │
          prints "2"               │    │
          calls countdown(1) ──┐   │    │
                               │   │    │
              countdown(1) starts│  │    │
                 prints "1"     │   │    │
                 calls countdown(0)│  │    │
                                 │ │   │    │
                     countdown(0) starts ←─ smallest, deepest call
                        prints "done!"
                        returns          → back to countdown(1)
                 countdown(1) returns    → back to countdown(2)
              countdown(2) returns       → back to countdown(3)
       countdown(3) returns              → all done
Enter fullscreen mode Exit fullscreen mode

Notice: every call waits for the next one to finish. Sticky notes pile up until the smallest one finishes. Then they unwind in reverse order.

That pile of paused calls is what the computer calls the call stack.

Loop vs recursion (same job)

The countdown above could also be a loop:

function countdown(n) {
  for (let i = n; i > 0; i--) {
    console.log(i);
  }
  console.log("done!");
}
Enter fullscreen mode Exit fullscreen mode

Same output. But:

  • Loop: one variable i, one execution context. Memory usage is constant.
  • Recursion: one execution context PER call. Calling countdown(1000000) would crash with "Maximum call stack size exceeded" because a million sticky notes don't fit in memory.

When recursion shines

Recursion is great when the problem is naturally nested:

  • Walk a folder tree (folders inside folders inside folders).
  • Parse JSON / HTML (objects inside objects).
  • Solve a maze (try a path, if dead end, back up and try another).
  • Math: factorial, Fibonacci, tree traversals.

Anything where "the smaller version of the problem looks just like the bigger version" is a good fit.

When to avoid recursion

  • Long flat sequences (counting from 1 to a million, walking pages of an API). A loop is faster and safer.
  • Anywhere the depth could be unbounded by user input. Loop or you risk a stack overflow.
  • Languages without tail-call optimisation (JavaScript / Node falls here). Even "tail recursion" still grows the stack in V8.

The mental shortcut

Loop Recursion
One sticky note, reused N times N sticky notes, all alive at once until the deepest one finishes
Constant memory Memory grows with depth
Best for: flat sequences Best for: nested / tree-shaped data

Recursion = a function that calls itself, with a base case to stop.
The cost is paid in stack space — every call lives until the inner one returns.

Top comments (0)