What makes a function pure, and why does it matter?
A pure function has two properties. First, when you give it the same arguments it always returns the same result, and it does not depend on anything outside of its parameters. Second, it causes no side effects that other code can observe. It does not change the arguments it was given, it does not modify any object or variable outside itself, and it does not do input or output work such as writing to the console, reading a file, or calling an API.
That definition has consequences that are worth spelling out. A pure function is easy to test, because you call it and you compare the result. It is safe to call again and again and in any order. It is safe to share between threads or between concurrent requests, because two calls cannot get in each other's way. And it is safe to cache, because a given input always leads to the same output, which is the whole basis of memoisation.
The payoff shows up in practice when something changes. If a function reads a global variable or reaches into a database, then changing the database changes the behaviour of the function, and you cannot test it without arranging the whole world around it. If the function takes everything it needs as arguments and returns a result, then the change stays contained.
There are two honest caveats. Strict purity is not always practical or desirable. A function that formats a date needs the current time, and the simplest way to get it is to read the clock, which is a side effect. The practical answer that many teams use is to inject the clock, or a source of random numbers, as a parameter. That keeps the logic testable while the wiring stays impure. Logging is a side effect too, so a function that logs as well as returning a value is not pure, even though it feels harmless.