As with everything in software architecture: everything is a compromise.
At large scale, and for application running on end-user devices, I try to keep as much as possible complexity in the software because you don't pay for its execution.
But again, that's a compromise that depends on scale and infrastructure costs.