Recursion is when a function calls itself as part of its own execution. Instead of solving a problem all at once with a loop, a recursive function breaks the problem down into a smaller version of itself, solves that smaller version, and keeps going until it reaches a point simple enough to solve directly. That stopping point is called the base case and it is the most important part of any recursive function — without it the function would call itself forever and crash the program.
The classic way to think about recursion is the Russian nesting doll. To open the whole set you open the outer doll, which contains another doll, which contains another, and so on until you reach the smallest doll that contains nothing — that is your base case. Then everything resolves back out in order.
Recursion tends to produce clean and elegant code for problems that are naturally self similar — things like traversing folder structures, processing trees, calculating factorials, and generating fractals. However it comes with a cost. Every function call takes up memory on the call stack, and if your recursion goes too deep before hitting the base case the stack runs out of space and crashes — this is called a stack overflow. For very deep problems an iterative approach with a loop is often safer and more efficient, but recursion remains one of the most important concepts to understand in programming.