Recursion is defined as a technique where a function calls itself, either directly or indirectly. It involves breaking a problem down into smaller sub-problems until it reaches a base case. For recursion to work properly, it needs a base case where the problem can be solved without further recursion, and each recursive call must make progress towards the base case. While recursion can provide elegant solutions, it uses more memory and time than iterative approaches like loops. Common pitfalls are not having a base case, not making progress on each call, or using too many resources on each recursive call.