SpaceStack
Menu
Workflow

How to profile and fix a slow web app

A methodical workflow for finding and fixing what actually makes a web app slow — measure real users first, find the biggest bottleneck, fix it, and prove the win. From an engineer who has shipped 30% speedups on slow devices.

Published Jul 4, 2026 • Updated Jul 4, 2026

Stylized cyberpunk illustration used as the editorial avatar for Daniel P.
Tech Lead Senior Software Engineer · Oslo, Norway
Outcome
A measurably faster web app, with the biggest bottleneck found and fixed, and a before/after you can prove.
For
Solo developers, small engineering teams and tech leads who own a web app's performance.
Read time
~15 min

Why most speedups fail

I have spent years making software faster, including squeezing WebGL and web apps onto slow devices where every millisecond showed. The most common mistake I see is not a lack of skill — it is optimizing the wrong thing.

Someone feels the app is slow, guesses at a cause, spends two days rewriting it, and the app is exactly as slow as before. The bottleneck was somewhere else entirely.

This workflow exists to stop that. The order matters: measure, find the biggest cause, fix that one thing, prove it. Guessing is not allowed.

The whole workflow at a glance

From 'it feels slow' to a proven fix
  1. 1
    Measure real users
    Capture field data from real devices, not just your laptop.
  2. 2
    Profile
    Find the single biggest bottleneck before touching code.
  3. 3
    Fix the biggest thing
    Assets, JavaScript, caching or backend — the top cause only.
  4. 4
    Re-measure
    Prove the win with the same measurement you started from.
  5. 5
    Budget & alert
    Lock in the gain so a future deploy can't quietly undo it.

Step 1: Measure real users first

Before you open a single file, get data from real visitors. Your fast laptop on office fibre is the least representative device your app will ever run on.

Pull field data — real Core Web Vitals from actual users — and look at the 75th and 95th percentile, not the average. The average hides the users who are suffering. If you have no field data yet, that is step zero: add a monitoring tool.

Sentry product screenshot
Sentry logo
Sentry
Best for: Errors + performance in one tool

Ties slow transactions back to the exact code, so measuring and fixing happen in one place.

Open Sentry
PageSpeed Insights product screenshot
PageSpeed Insights logo
PageSpeed Insights
Best for: Free first diagnosis

Free Google tool showing lab and real-user Core Web Vitals for any URL. A great first look.

Open PageSpeed
Cloudflare Web Analytics product screenshot
Cloudflare Web Analytics logo
Cloudflare Web Analytics
Best for: Free real-user monitoring

Free, privacy-first real-user metrics with no cookies — an easy way to see real field data.

Open Cloudflare

Start with real-user data. Confirm current free tiers before committing.

Step 2: Profile to find the one bottleneck

Now open the profiler — Chrome DevTools’ Performance and Network panels are enough to start. Load the page as a real user would: throttle to a mid-tier phone and a slow network in DevTools, then record.

You are looking for the single biggest cost, sorted by impact:

Where web slowness usually hides
Usually the problem
  • Huge unoptimized images
  • Too much JavaScript on the main thread
  • No caching / no CDN
  • Render-blocking scripts and fonts
Sometimes the problem
  • Slow database queries (N+1)
  • Slow third-party scripts
  • Layout shift from unsized media
  • Chatty, unbatched API calls
Check these in order of how often they're the real culprit for a small team.

Step 3: Fix the highest-impact cause

Fix one thing — the biggest — then re-measure. Do not fix five things at once, or you will not know what worked. The usual high-leverage fixes, roughly in order of bang-for-buck:

  1. Optimize images. Compress, resize, use modern formats and lazy-load below the fold. Often the single biggest LCP win.
  2. Ship less JavaScript. Code-split, remove dead dependencies, defer non-critical scripts. The main lever for responsiveness (INP).
  3. Add caching and a CDN. Cheap, huge, and no app rewrite needed.
  4. Fix the backend. Hunt N+1 queries, add indexes, cache hot results.
  5. Reserve space for media. Set width/height to kill layout shift (CLS).

Step 4: Prove the win

Re-run the exact measurement from Step 1, under the same throttling. Compare the numbers. A real win looks like “LCP at the 75th percentile went from 4.1s to 2.2s,” not “it feels snappier.”

Field data takes days to update because it reflects real traffic, so use lab measurements for the immediate before/after and watch field data confirm it over the following week.

Step 5: Keep it fast with a budget

Performance rots. A future deploy adds a heavy library and quietly undoes your work. Lock in the gain with a performance budget and alerts.

Make the speed stick
  1. 1
    Set a budget
    Max bundle size and target LCP/INP/CLS. Write it down.
  2. 2
    Monitor continuously
    Keep a real-user tool running so regressions surface fast.
  3. 3
    Alert on regressions
    Get paged when a metric crosses the budget, before customers notice.
  4. 4
    Review after big changes
    Re-check performance after major features or dependency bumps.

Common mistakes

  • Optimizing without profiling. The number one time-waster. Measure first.
  • Testing only on your machine. Throttle to a real phone and network, or you will miss the real pain.
  • Chasing a 100 Lighthouse score. Real-user field data is what matters, not a vanity lab number.
  • Fixing many things at once. You lose the ability to know what actually helped.
  • No budget afterward. Without a guardrail, the app slowly gets slow again.

Next steps

Keep reading