This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry.
🟣 It took a little bit getting used to understanding Sentry, learning how to navigate and what can be done. In my spare time over the last few weeks, I was able to do some poking around. I connected my page at annavillarreal.com since it has a fair amount of content coming in, to make it more interesting to analyze.
Investigation
I explored the dashboard, trying to figure out how to get readings from my traffic, which didn't take to long to figure out. I found traces particularly interesting. Why? Because this is where I discovered an actual performance issue.
A trace shows a 4,229ms pageload. Here's what's driving the slowness:
The critical path is sequential and bottlenecked at the server:
| Span | Duration |
|---|---|
| browser.DNS | 107ms |
| browser.connect | 553ms |
| browser.TLS/SSL | 281ms |
| browser.request (TTFB) | 2,068ms |
| browser.response | 1,052ms |
Findings
-
browser.requestat 2,068ms. This means that server took over 2 seconds just to start sending a response. That alone is ~49% of the total trace time. - Notably,
browser.responseat 1,052ms (slow download) consumes an additional ~3.1 seconds just in the request/response cycle.
The average for this pageload is ~194ms, so the server response time being 2 seconds is the primary reason for the spike. I really don't want a new user waiting 4 or more seconds when visiting my page, that's a long time, relatively speaking.
Understanding the Data
Using Seer, Sentry's built-in AI, I was able to quickly understand the information presented before me. It explained to me that:
- The GET https://dev.to/api/articles call averages 361ms and hits 1.37 seconds at p95 — so it's consistently adding latency to your pageload, and on bad days it's the biggest bottleneck.
- Googlefonts was also eating up some pageload time:
Ways to Improve
- Instead of the browser fetching dev.to articles on every pageload, the backend can fetch and cache them. By serving the cached result to the browser, load time is reduced. Articles don't change every second, so a background cache refresh leaves users largely unaffected.
- Keep the client-side fetch, but make sure it doesn't block the initial render. Load the dev.to content lazily after the page is interactive and use a loading skeleton so users see content quickly while articles load in the background. Note: This does not make the call faster but removes it from the critical path. Makes a pleasant experience for visitors viewing non-critical data.
Particularly Interesting Performance Feature
The p95 problem specifically is handled by proxy_cache_background_update + proxy_cache_use_stale: when the 15-minute TTL expires, the next visitor gets the existing copy right away while nginx refreshes behind them. Nobody waits on dev.to after the first fill, and if dev.to is down or rate-limiting, the blog section keeps rendering off the last good copy for up to a day rather than showing "could not load posts."
Changing the cache has a real impact, the data over the last week proves it. Looking at the javascript-microserver project's performance over the past week I see:
Overall pageload (p50) trend for annavillarreal.com/
| Date | p50 | p95 |
|---|---|---|
| Jul 31 | 708ms | 708ms |
| Aug 1 | 655ms | 1.6s |
| Aug 2 | 2.1s | 2.6s |
| Aug 3 | 2.6s | 3.5s |
| Aug 4 | 3.3s | 4.2s |
| Aug 5 | 1.3s | 2.5s |
That's a ~60% p50 improvement on Aug 5 vs Aug 4. Fantastic.
Why the Cache Matters
The page fetches articles via GET /api/devto, which internally calls https://dev.to/api/articles. Without caching, that server-side call to dev.to was taking anywhere from 74ms to 832ms depending on the day. In this current trace, GET /api/devto completed in just 90ms, which is well below even the best prior direct-to-dev.to call. It is now being served from cache rather than hitting the external API.
In this case, the cache particularly valuable because it insulates the page from upstream latency entirely, streamlining performance for visitors to the page.
Takeaway
I really enjoyed the challenge of exploring this tool and trying to make sense of it. I can definitely see how it could lead to massive performance optimizations for end users, as I experienced it myself. I am happy I found a performance issue before many users might have the bad experience of a slow page load. Gross!



Top comments (4)
The 2,068ms TTFB jumping out as 49% of the trace is the part that sticks with me — that latency lives entirely outside the browser, so it's invisible to most frontend tooling until someone correlates it with a real user complaint. The nginx
proxy_cache_background_update+proxy_cache_use_staleapproach you landed on is the right move for near-static third-party content; the sharpest edge case I've seen with that pattern is the cold-cache first request, where the miss still blocks the caller for the full upstream round-trip — worth a dedicated p95 alert on that path to see whether first-fill has its own tail. Sentry's ability to surface the dev.to API as a contributor at p95 rather than just on average is exactly the kind of thing that gets deprioritized until you have the trace to prove it isn't noise.Thank you for stating that so elegantly. That is one of the reasons that sentry shines, you are able to catch the issues from every angle, hopefully before they would become part of the user's experience! 😂 I can see how this would enhance the experience, and stop a million tiny frustrations from becoming one giant frustration.
In fact, building with such a tool from the very beginning might even stop engineers from building architectures a certain way. Like "hey, dont do that. Data from sentry has showed us it creates x which could pile up and cause y in the future." Or something along those lines.
Just a guess, but I think I might be right.
Ah, we can use sentry for that. I always use it to get error notifications
I think the trace is so cool. Assigning latency to culprits and finding fixes feels like success. The visuals are great. Its so helpful. I found it entertaining and would like to spend more time on this. ✨️