Most performance work is removal. You find the two megabyte bundle, the blocking font, the image nobody sized, and you take them away. That gets a page from four seconds to one, and it is satisfying work because every change shows up on the chart.
The last hundred milliseconds are not like that. Nothing is obviously wrong any more. The page is already fast by any score you care to run, and it still does not feel instant.
Measure the wait, not the load
People do not experience your load event. They experience the gap between wanting something and seeing it. In production web applications, users do not care that your JavaScript bundle finished downloading in 400ms if the main thread locks up for 250ms parsing client-side trees. So I measure three moments: the first thing they can read, the first thing they can tap, and how long that first tap takes to answer.
Rather than guessing synthetic Lighthouse scores from high-end development laptops in Adama, we hooked real user monitoring directly into our client layout using the PerformanceObserver API. We captured Interaction to Next Paint (INP) across real mobile network connections with varying latency profiles.
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.duration > 100) {
reportMetric(entry.name, entry.duration);
}
}
}).observe({ type: 'event', buffered: true, durationThreshold: 40 });Eliminate network waterfalls first
Network round-trips over cellular hops are expensive. A typical mobile request in East Africa takes 80ms to 120ms just for TLS handshake and initial TCP slow-start. When a React Server Component fetches user permissions, waits for the response, and only then triggers a nested database query for dashboard items, you have built a serial waterfall that guarantees an unnecessary delay.
Parallelizing independent data dependencies at the edge and streaming the page shell immediately with React Suspense transforms this equation. By pushing cache tags through Next.js and pre-resolving read-only queries with Prisma in parallel Promise.all blocks, the initial HTML stream arrives with zero serial hops.
// Parallelize database queries to prevent serial waterfall locks
const [userProfile, activeProjects, systemMetrics] = await Promise.all([
getUserProfile(userId),
getActiveProjects(userId),
getSystemMetrics(userId),
]);Optimistic UI and when to stop
Fast is a number. Instant is a feeling, and it starts at about a hundred milliseconds. When an interaction cannot be completed on the server within 80ms, waiting for the HTTP round-trip feels sluggish no matter how optimized your PostgreSQL queries are.
Optimistic updates bridge this threshold: mutate the local UI state synchronously on tap, commit the speculative change to your local query cache, and rollback cleanly if the server rejects the mutation. Below eighty milliseconds, human perception ceases to register improvements. Stop optimizing numbers that users cannot feel, and spend that budget on transaction reliability.
