> Plus in most cases showing error messages too fast is terrible UX.
The solution to that problem is to debounce or throttle your error messages. That allows you to report validation issues to the user quickly, but not overwhelmingly fast, before sending a network request potentially across the Earth and back.
Showing error messages on the client side is not too fast or bad UX. Let's say someone entered an invalid credit card. Or an invalid email. Why even let that touch the backend?
Note that frontend forms libraries allow a lot of choice over when to show error messages.
Validating in multiple places doesn't mean 2x the code. You can validate on both the client and the server using the same code. One of the charms of server-side JS.
Those charms can turn tiresome rather quickly once you discover those server-side JS libraries you're popping like candies are adding bloat and security vulnerabilities once they're shipped to the client side.
You can split the validation in multiple functions/modules which you can then use both at submission or per step/page.
Also, it seems you're implying having two validation systems (on the client and server) is actually good?