Ruby & Rails

The server was fast and the page still felt slow

Server time is a fraction of what a user experiences. The rest is fonts, images, and what the browser is blocked on.

22 October 2025 2 min read Mohammad Aaquib Jawed

An 80ms response and a page that takes three seconds to feel usable is an entirely normal combination, and application logs will show nothing wrong.

What blocks rendering

Stylesheets block rendering by design — the browser will not paint until it knows how things look. Which means CSS size and delivery are directly on the critical path.

Synchronous scripts in the head block parsing entirely. Modules and deferred scripts do not, which is why the modern default is far better than what many older applications still do.

Fonts are the subtle one. A web font that has not loaded leaves text invisible or swapped, and the resulting shift is one of the most noticeable jank sources on the web. A sensible font-display and preloading the faces you use above the fold fixes most of it.

Digests and cache headers

Rails fingerprints asset filenames with a content hash. That is what makes an aggressive cache policy safe: the filename changes when the content does, so a year-long cache lifetime cannot serve stale content.

Set it and stop thinking about it. Assets are the easiest cacheable thing you own, and serving them with short lifetimes is pure waste.

Compression matters as much as caching. Text assets compress dramatically, and modern algorithms noticeably beat the older default. A layer in front of the app can handle compression and caching without application code.

Images are usually the weight

Images are typically most of a page's bytes, and the wins are unglamorous.

Serve the size actually displayed rather than scaling a large file in the browser. Use a modern format. Lazy-load anything below the fold. And always set width and height, so the browser reserves space and the page does not jump when the image arrives — that shift is one of the most irritating things a page can do and it is a one-attribute fix.

Reserve space before the asset arrives. Most layout shift is a missing dimension, not a slow network.

Measure what users get

Lab tools on a fast laptop over office wifi describe a device nobody has.

Field data — real devices, real networks — is the honest measurement, and it usually shows the bottleneck is not the server at all. Which is worth knowing before you spend a sprint shaving 20ms off a response that arrives 2 seconds before anything is visible.

All writing Reply by email