---
title: Optimistic Update
slug: optimistic-update
kind: pattern
summary: Show the result of an action immediately, send it in the background, and reconcile honestly if it fails — so a fast action feels instant instead of waiting on a network round trip.
problem: >-
  Ticking a checkbox spins for 400 milliseconds before anything changes. Done
  forty times an hour, the interface feels like it is arguing with the person,
  even though every individual wait is short.
family: [edit, act, recover]
data_shape: [record]
principles: [friction, orientation]
interaction: [feedback, editing]
density: low
complexity: medium
status: stable
visibility: public
use_when:
  - The action almost always succeeds — a toggle, a reorder, a tick, a like.
  - The result is fully predictable from what the person did.
  - The action repeats often enough that the round trip is felt.
  - Undoing it visually is straightforward if the server disagrees.
avoid_when:
  - The server decides the outcome — a payment, an availability check, anything that can be refused for reasons the client cannot know.
  - Failure is common, so people would routinely watch changes reverse.
  - The consequence is serious enough that a false confirmation would matter.
  - The response contains information the client could not have predicted.
alternatives:
  - slug: loading-skeleton
    when: The wait is a load rather than an action, and the outcome is not predictable.
  - slug: autosave
    when: The concern is durability of composed content rather than latency on a discrete action.
ask_leo: |
  Make these actions optimistic.

  - Apply the change in the interface immediately, then send the request.
  - Do not show a spinner on the changed element. The point is that it looks
    finished. A very subtle pending hint is acceptable; a blocking one is not.
  - If the request fails, revert the element to its previous state, explain what
    happened in a message near the element, and offer a retry. Never revert
    silently — a value that quietly snaps back is read as the person's own
    mistake.
  - Keep the person's other work intact while reverting. Do not reload the
    screen or reset unrelated state.
  - If the same item is changed several times quickly, make sure the last state
    wins rather than whichever response arrives last.
  - Do not apply this to anything where the server decides the outcome, or where
    a wrongly-shown success would matter.
related:
  - title: Inline Editing
    url: /patterns/inline-editing
    summary: The most common place this pattern is applied, and where reverting must be visible.
  - title: Confirmation vs Undo
    url: /patterns/confirmation-vs-undo
    summary: The related judgment about reversibility and who bears the risk.
---

## 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:

1. **Immediate visual result**, with no spinner on the thing that changed.
2. **A background request** whose success is the normal, silent case.
3. **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.
