Skip to main content
Every rule runs by default, so one request reports every error. Some rules, though, only make sense after another: a database lookup is wasted on an email that is not even an email, and its answer would only add noise. Put both in failFast { }: its rules run in order, and the ones after the first failure are not evaluated.
Newsletter.kt
The rules after the block, and the other properties, run as usual: failFast only shortens its own block.

What counts as one step

Each call in the block is one step. An each { } or a valid() counts once, with all its elements: when any element fails, the steps after it are skipped, and every violation of that step is reported.
failFast also works inside a branch of or, where it makes the branch report only its first failure.

It skips rules, not code

The rules are declared first and checked later. Work written in the block but outside a rule runs every time, even when the rules before it fail:
Put the work inside constraint { }, after the rule it depends on.