{"slug":"optimistic-update","meta":{"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.\n\n- Apply the change in the interface immediately, then send the request.\n- Do not show a spinner on the changed element. The point is that it looks\n  finished. A very subtle pending hint is acceptable; a blocking one is not.\n- If the request fails, revert the element to its previous state, explain what\n  happened in a message near the element, and offer a retry. Never revert\n  silently — a value that quietly snaps back is read as the person's own\n  mistake.\n- Keep the person's other work intact while reverting. Do not reload the\n  screen or reset unrelated state.\n- If the same item is changed several times quickly, make sure the last state\n  wins rather than whichever response arrives last.\n- Do not apply this to anything where the server decides the outcome, or where\n  a wrongly-shown success would matter.\n","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."}]},"body":"## Anatomy\n\n```\n  click ──▶ interface updates NOW ──▶ request sent ──┬─▶ 200: nothing more to do\n                                                     │\n                                                     └─▶ 500: revert the element,\n                                                         say why, offer retry\n                                                         ▲ never silent\n```\n\nThe pattern is three commitments:\n\n1. **Immediate visual result**, with no spinner on the thing that changed.\n2. **A background request** whose success is the normal, silent case.\n3. **A loud, local failure path** — revert, explain, retry, all next to the\n   element.\n\nThe third is the whole pattern. Optimistic updates without an honest failure\npath are not optimistic, they are dishonest.\n\n## Why it works\n\nIt removes latency from the person's experience of a *predictable* action. When\nthe outcome is genuinely determined by what they did, waiting for the server to\nconfirm what you already know is pure overhead — the round trip is protecting\nagainst a case that almost never happens.\n\nThe payoff is largest exactly where the friction is worst: repeated small\nactions. One 400ms wait is nothing; forty of them in an hour is what makes an\ninternal tool feel heavy.\n\n## The word \"predictable\" is doing all the work\n\nThe pattern is only safe when **the client can compute the outcome**. A checkbox\ntick is predictable. A \"book this slot\" is not — someone else may have taken it,\nand the client cannot know.\n\nThe test: *if I show the success now, could the server plausibly disagree for a\nreason I could not have known?* If yes, do not be optimistic. Showing a booking\nconfirmed and then withdrawing it is worse than a one-second wait, because the\nperson has already told someone.\n\n## Getting it wrong\n\n- **Silent revert.** The most damaging version: the value snaps back with no\n  message, and the person assumes they mis-clicked. They will re-do it, and\n  it will fail again.\n- **Optimism on server-decided outcomes.** Bookings, payments, stock. This is\n  how a product tells someone they succeeded when they did not.\n- **A spinner on the optimistic element**, which cancels the benefit entirely.\n- **A full page reload on failure**, throwing away everything else in progress.\n- **Race conditions** on rapid repeats, where an older response overwrites a\n  newer state.\n\n## Exemplars\n\n**Gmail's star** is the canonical case: predictable, frequent, trivially\nreversible, and the round trip is invisible.\n\n**Linear** applies it broadly and pairs it with a genuinely loud failure path,\nwhich is what makes the aggressiveness acceptable rather than reckless.\n\n**Any checkout flow** is the counter-example worth remembering — nobody shows an\noptimistic \"payment successful\", because the server is the only thing that knows.\n\nThe extractable rule: **be optimistic about what the person decided, never about\nwhat the server decides.** The line is not risk appetite, it is who holds the\ninformation.\n"}