Recursion — a function that calls itself — is one of those concepts that stays baffling right up until it suddenly does not. The block for most people is trying to trace every call in their head, watching the stack grow, and getting lost three levels deep. That is the wrong way to think about it.
The trick is to stop tracing and start trusting.
The leap of faith
The mental move that makes recursion click is this: assume the function already works for a smaller version of the problem, and only write the logic for one step plus how to combine it. You do not trace the whole thing; you trust the smaller call to return the right answer, and focus on what you do with it.
To sum a list, you say: the sum is the first item plus the sum of the rest — and you trust "the sum of the rest" to be correct. That trust is not naïve; it is the whole technique.
The base case is non-negotiable
Every recursive function needs a base case: a smallest input it answers directly, without recursing. Without it, the function calls itself forever and the program crashes as the call stack overflows. The base case is what stops the descent — the empty list sums to zero, and everything else builds up from there.
A useful checklist: does each call move toward the base case, and does the base case actually get reached? If either answer is no, you have an infinite recursion waiting to happen.
When to reach for it
Recursion shines on problems that are naturally self-similar — trees, nested structures, "a thing made of smaller things like itself". For those, recursive code is often dramatically clearer than the loop-and-stack equivalent. For simple linear work, a plain loop is usually clearer and avoids deep call stacks.
Learn to recognise the self-similar shape, trust the smaller call, and always pin down the base case first. Do that and recursion stops being magic and becomes just another tool.