Anatomy
click ──▶ interface updates NOW ──▶ request sent ──┬─▶ 200: nothing more to do
│
└─▶ 500: revert the element,
say why, offer retry
▲ never silent
The pattern is three commitments:
- Immediate visual result, with no spinner on the thing that changed.
- A background request whose success is the normal, silent case.
- A loud, local failure path — revert, explain, retry, all next to the element.
The third is the whole pattern. Optimistic updates without an honest failure path are not optimistic, they are dishonest.
Why it works
It removes latency from the person's experience of a predictable action. When the outcome is genuinely determined by what they did, waiting for the server to confirm what you already know is pure overhead — the round trip is protecting against a case that almost never happens.
The payoff is largest exactly where the friction is worst: repeated small actions. One 400ms wait is nothing; forty of them in an hour is what makes an internal tool feel heavy.
The word "predictable" is doing all the work
The pattern is only safe when the client can compute the outcome. A checkbox tick is predictable. A "book this slot" is not — someone else may have taken it, and the client cannot know.
The test: if I show the success now, could the server plausibly disagree for a reason I could not have known? If yes, do not be optimistic. Showing a booking confirmed and then withdrawing it is worse than a one-second wait, because the person has already told someone.
Getting it wrong
- Silent revert. The most damaging version: the value snaps back with no message, and the person assumes they mis-clicked. They will re-do it, and it will fail again.
- Optimism on server-decided outcomes. Bookings, payments, stock. This is how a product tells someone they succeeded when they did not.
- A spinner on the optimistic element, which cancels the benefit entirely.
- A full page reload on failure, throwing away everything else in progress.
- Race conditions on rapid repeats, where an older response overwrites a newer state.
Exemplars
Gmail's star is the canonical case: predictable, frequent, trivially reversible, and the round trip is invisible.
Linear applies it broadly and pairs it with a genuinely loud failure path, which is what makes the aggressiveness acceptable rather than reckless.
Any checkout flow is the counter-example worth remembering — nobody shows an optimistic "payment successful", because the server is the only thing that knows.
The extractable rule: be optimistic about what the person decided, never about what the server decides. The line is not risk appetite, it is who holds the information.