Skip to content

Speed & Perceived Performance

A UX principle for coding agents. Also covers performance, latency, perceived performance, responsiveness, local-first, optimistic updates, and 1 more.

Show all 7 aliases

performance, latency, perceived performance, responsiveness, local-first, optimistic updates, prefetch

Speed is part of the product experience. Users notice the time between intent, acknowledgement, and a useful result; they do not care which layer caused the delay.

This principle covers product decisions: response budgets, loading behavior, prediction, and architecture choices. Use UI performance for rendering and profiling, perceived speed for motion, and interactions for loading and optimistic-update patterns.

Budget the User-Visible Milestones

Do not give an entire feature one vague performance target. Budget the moments a user can perceive:

  • Acknowledge input immediately. Aim to show a pressed, selected, opened, or pending state within 100ms. This is an ideal feedback target, not a promise that every network-backed task will finish in 100ms.
  • Keep direct manipulation inside the frame budget. Dragging, scrolling, drawing, and typing must update with the display. Move expensive work out of that path.
  • Deliver a useful result as soon as possible. Define this per journey: the requested route is usable, search results can be acted on, or an edit appears in context.
  • Explain longer work before attention drifts. Preserve the current context and show progress when a task can take roughly a second or more. For multi-step work, say what is happening and whether the user can leave safely.

Acknowledgement and completion are different milestones. An optimistic row update can acknowledge an edit instantly, but it must not claim the server accepted the change until confirmation arrives.

Measure Journeys, Not Averages

Measure real user journeys at the slow end of normal use. A fast median can hide a broken experience for a large group of users.

  • Track field data at the 75th percentile, split by mobile and desktop where the populations differ.
  • Use the current Interaction to Next Paint guidance as a baseline; at publication, a good INP is 200ms or less at the 75th percentile. Recheck the threshold when setting a long-lived budget.
  • Add product timings for milestones the browser metric cannot describe: route usable, first meaningful result, mutation acknowledged, mutation confirmed, and recovery completed.
  • Segment by device, network, account size, and route when those factors materially change the result.
  • Put budgets in regression checks or dashboards, and investigate sustained regressions rather than isolated samples.

Lab traces explain a problem. Field data tells you whether users have one. Use both, and verify each optimization against the journey it was meant to improve.

Keep Useful State While Work Continues

Waiting should not erase information the user already has.

  • Keep the previous view available during background refreshes and transitions when it remains valid.
  • Use a skeleton only when the shape of first-load content is known and no useful content can be shown yet.
  • Show local feedback before starting expensive work: keep the control pressed, insert the draft row, or expose a pending state.
  • Use optimistic updates only for actions that usually succeed and can be reversed or reconciled clearly.
  • Disable only the control that cannot be repeated safely. Do not freeze the whole page for one mutation.
  • Never add a minimum loader duration merely to make an animation visible. A fast response should look fast.

Failure belongs to the same flow. Preserve the attempted value, explain what failed, and offer retry, undo, or conflict resolution without making the user reconstruct their work.

Choose Architecture Proportionate to the Product

Remove network waits from frequent interactions with the simplest architecture that meets the product's needs:

  1. Cache stable reads and refresh them in the background.
  2. Apply reversible mutations optimistically and reconcile the response.
  3. Add a durable offline queue when work must survive reloads or intermittent connectivity.
  4. Consider a local database and sync engine when collaboration, offline use, or repeated high-frequency data work justifies the operational complexity.

Local-first is not a default requirement. It introduces conflict resolution, migrations, cache isolation, storage limits, and recovery behavior. Most products should begin with a client cache and targeted optimistic updates, then adopt stronger local persistence only when measured journeys or explicit offline requirements demand it.

If a product adopts a durable offline queue, make replay safe. Give each mutation a stable operation ID or idempotency key so retries cannot apply it twice. Preserve ordering where actions depend on earlier actions, define how conflicts are resolved, and ask the user to review work that became stale while disconnected.

The server remains authoritative for identity, permissions, billing, inventory, and other invariants. A local cache is a responsiveness tool, never an authorization boundary.

Move Work Earlier When Intent Is Clear

Prediction can remove a wait, but inaccurate prediction spends the user's bandwidth and device resources for no benefit.

  • Prefetch route code or data on strong intent signals such as focus, hover, or an advancing wizard step.
  • Prioritize the one or two most likely next destinations instead of preloading every route.
  • Reuse the prefetched response for the real navigation and cancel work when intent changes.
  • Respect data-saver settings, metered connections, battery constraints, and server load.
  • Never trigger mutations or access-sensitive side effects through speculative loading.

Use analytics to confirm that predictions are accurate enough to justify their cost.

Make Startup Fast Without Crossing Privacy Boundaries

Render the smallest useful, account-neutral shell while authentication and private data load. Safe cached preferences such as theme or navigation width may be applied before session validation. Do not paint cached messages, account data, billing details, or other private content until the current identity is verified.

Keep disposable caches isolated by account. Clear them on logout or account switch, and define how stale data is invalidated.

Treat pending offline work separately. Bind it to the account that created it. On logout or account switch, choose one explicit outcome: sync it first, ask the user to keep or discard it, or retain it for that account and resume only after that account signs in again.

Ship only the code and assets needed for the first useful view; defer optional editors, analytics, and route-specific features until they are needed.

Shorten Repeated Paths

Engineering can make one interaction fast; product design determines how many interactions a task requires.

  • Give frequent actions direct, visible paths.
  • Add keyboard shortcuts for repeated expert workflows, with discoverable hints and an equivalent pointer path.
  • Use a command palette when the product has enough navigation and actions to benefit from a common search surface. Do not add one to a small app by reflex.
  • Preserve selection, scroll position, filters, and draft state when users move between related views.

Optimize the whole journey, not a single fast button inside a slow sequence.

Make Synchronization Legible

When local and remote state can differ, users need to know which state they are seeing. Use clear, quiet states such as pending, saved, offline, retrying, and conflicted. Do not show a success message while a change is only queued.

Reconciliation should be deterministic:

  • Confirm success without moving or resetting the user's context.
  • Roll back safely or retain the attempted value when the server rejects a change.
  • Explain conflicts in the language of the task, not the storage model.
  • Never silently discard offline work.

Checklist

  • Input receives visible acknowledgement within the interaction budget
  • Acknowledgement, useful result, and confirmed completion are measured separately
  • Field performance is reviewed at the 75th percentile on representative devices
  • Existing content remains usable during background refreshes
  • Optimistic actions are reversible and expose pending or failure states
  • Local-first complexity is justified by collaboration, offline, or measured needs
  • Durable offline retries are idempotent or deduplicated and define ordering, conflicts, and stale-work behavior
  • Private cached content waits for verified identity
  • Pending offline work stays with its account and is handled explicitly on logout or account switch
  • Prefetching follows strong intent signals and respects resource constraints
  • Frequent workflows have short, discoverable paths
  • Offline, retrying, saved, and conflicted states are understandable
  • Rendering, motion, and loading details follow the linked UI and interaction principles

Use this guidance in your coding agent

Install the Better Design MCP once. Your agent then loads this page with one call.

get-ux-principle({ topic: "speed" })
claude mcp add --scope user better-design --transport http https://better-design.com/api/mcp --header "Authorization: Bearer <YOUR_API_KEY>"
Browse related design systems