Web Application Performance: What to Fix First?

Jackson NeoJackson Neo
Web Application Performance: What to Fix First?

Web Application Performance: What to Fix Before Rebuilding

When a web application feels slow, the tempting answer is a rebuild on a newer framework. Sometimes that is right, but the cause can also be something specific: too many third-party scripts, a page loading far more data than it shows, or a report that does all its work while the user waits. Problems like these can be fixed without starting again, and a rebuild that does not address them can end up just as slow.

This guide is for business owners whose application loads slowly, lags when people use it, or struggles at busy times. It explains how to work out what kind of slowness you have, how to measure it, what usually causes it and how to judge whether a developer's proposed fix, or proposed rebuild, is justified.

Start by naming the kind of slowness

"The app is slow" can mean several different things, and each one points to different causes.

What users noticeWhere to look first
Pages take a long time to appearPage weight, JavaScript, images, third-party scripts, server response time
The page has loaded, but clicks and typing feel laggyJavaScript running in the browser, large screens re-drawing too often
Searches, saves or reports take a long timeDatabase queries, the amount of data fetched, slow external services, heavy processing
Everything is fine until many people use it at onceServer capacity, database load, shared resources, work that should run in the background

Be as specific as you can when describing the problem to a developer. "Generating the monthly sales report takes over a minute" or "the customer list freezes when I type in the search box" gives them something to measure. It also lets you check later whether the fix worked.

Measure the affected workflow before changing anything

There are two kinds of performance measurement, and they answer different questions.

Lab tests load a page in a controlled setting: one device, one network speed, one location. Lighthouse, which also powers the lab section of Google's PageSpeed Insights, works this way. Lab tests are repeatable, which makes them good for diagnosing problems and comparing before and after a change.

Real-user (field) measurements come from actual visitors on their own phones, laptops and connections. Google's guidance on lab and field data explains why the two often disagree. Real users may have parts of the page cached, use slower or faster devices than the test, and interact with the page in ways a lab test cannot predict. Where both are available, Google recommends giving field data priority, because it reflects what users actually experience.

PageSpeed Insights shows field data for pages with enough public traffic. When a specific page lacks enough samples, it may show data for the whole site (origin) instead, so check which one you are looking at before using it to judge a particular screen. Many business applications sit behind a login or have a small number of users, so there may be no public field data at all. In that case you either collect your own real-user measurements, for example with Google's open-source web-vitals library, or rely on careful lab testing combined with feedback from the people who use the system.

We use PageSpeed Insights and Lighthouse for this work. They cover page loading well. For slow searches, saves and reports, the useful number is usually simpler: how long does it take from clicking the button to seeing the result, and where does that time go? Measure it with realistic data. A search that is instant with 200 test records can crawl with 200,000 real ones.

Before anyone changes anything, write down the starting point: the workflow, the timing, the device and network used, the amount of data and, for server-side problems, how many people were using the system at the time. Without that, nobody can show whether the work made a difference. If the problem only appears when many people use the system at once, a controlled load test is the way to reproduce it (see load testing a web application before launch).

Core Web Vitals in plain language

Google's Core Web Vitals are three measurements of the experience of loading and using a page:

  • Largest Contentful Paint (LCP) measures how long the main content takes to appear, such as the largest image or block of text. Good is 2.5 seconds or less. Poor is more than 4 seconds.
  • Interaction to Next Paint (INP) measures how quickly the page visibly responds when someone clicks, taps or types, across the whole visit. Good is 200 milliseconds or less. Poor is more than 500 milliseconds. INP replaced an older measurement, First Input Delay, in 2024.
  • Cumulative Layout Shift (CLS) measures unexpected movement of visible content during a page visit, for example when a late image pushes a button down just as someone tries to tap it. Good is 0.1 or less.

Google assesses these at the 75th percentile of visits, separately for mobile and desktop, so for each metric separately, at least three in four visits need to meet the target. INP can be measured in lab tools that simulate clicks and typing, but a standard Lighthouse page-load test involves no interactions, so it reports Total Blocking Time instead. That helps flag likely problems but can look fine even when real users experience lag, which is why field data is still needed to understand what users actually go through.

Core Web Vitals are useful, but they describe pages, and a business application is usually judged by tasks. A page can pass all three while the "generate invoice" button still takes 20 seconds. Track the timings that matter to your business alongside them: completing a search, saving a record, loading a dashboard, exporting a report.

On search rankings, Google says its ranking systems use Core Web Vitals, but there is no single page experience signal and good scores do not guarantee top positions. It will still show the most relevant content even when page experience is poor. Performance work is worth doing for your users. Treat any ranking benefit as a possible bonus, never a promise.

You will also see case studies linking speed to business results. Google's Renault case study, for example, found that faster loading on Renault's landing pages was associated with lower bounce rates and more completed lead forms. Results like these show speed can matter commercially, but they come from one company's site and traffic. They are not a forecast for your application.

Common causes in the browser

Too much JavaScript

JavaScript running on the browser's main thread competes with everything else the page needs to do, because the main thread can only do one thing at a time. Google's guidance treats any task taking longer than 50 milliseconds as a long task. While one is running, the page cannot respond to clicks or typing. Large JavaScript bundles also take longer to download and start, particularly on mid-range phones.

Common fixes include removing unused code and libraries, loading features only when they are needed (code splitting) and breaking heavy work into smaller pieces.

Large images, fonts and other assets

Oversized images slow down loading. So does an important image that is set to load lazily, which delays the main content that LCP measures. Serving images at the size they are displayed, in modern formats, and making sure the main image is loaded early are common improvements.

Third-party scripts

Chat widgets, analytics tags, review badges, A/B testing tools and marketing pixels all load code from other companies' servers. Google's guidance on third-party JavaScript notes that these scripts add network requests, can block the page from displaying, and can load their own copies of libraries the page already has. Each one may be small, but they add up, and you do not control how well any of them is built.

Screens that redraw too much

Some applications redraw large parts of the screen on every keystroke or update. A table with thousands of rows that re-renders as someone types in a filter box is a typical example. Vue's performance guide points out that rendering a list with thousands of items will be slow, and recommends showing only the rows currently on screen (known as virtualisation). React and other frameworks face the same issue.

Requests that wait for each other

A request waterfall happens when the page has to finish one request before it knows to start the next: load the page, then load the component, then fetch its data, then fetch related data. React's documentation describes fetching data inside components as a common cause of these network waterfalls and recommends fetching a page's data together, as early as possible.

A real example: a Shopify store slowed down by apps

A client came to us with a Shopify store built by another agency. The client had invested a lot in it, and the store had been loaded with a large number of apps (Shopify's name for plugins). Shopify itself lists apps among the biggest factors in store performance, because each one can add its own scripts and files to the storefront.

We reviewed the installed apps and removed the ones that were not doing anything useful, which cut unnecessary work from the storefront. App count alone is not the diagnosis, since some apps add no storefront code at all; what matters is what each one loads. Some of the remaining apps provided features simple enough to replace with a small amount of custom code that could be hosted at no extra cost, so we replaced those and removed the apps too. One detail matters with this kind of clean-up: Shopify notes that uninstalling an app does not always remove its code from the theme, so leftover code has to be checked as well.

The client had the option of a full rebuild. Optimising the existing store was the better value, because it kept the investment they had already made and was done for a single cost. They were happy with the result and moved onto one of our maintenance plans so we could continue looking after the store.

Common causes on the server

Inefficient database queries

A query that scans an entire table to find a few records, or a page that runs a separate query for every row it displays, can be fast with test data and slow in production. Developers can find these by measuring how long each query takes, then fix them with better queries, indexes or by fetching related data in one go.

Fetching more data than the screen needs

A list page that loads every customer record with every field, then shows 20 names, wastes time at every step: the database, the network and the browser. Fetching only the fields and rows the screen displays can make a noticeable difference, though it needs testing, because other features may rely on the data being removed.

Slow external services

If a page waits for a payment provider, shipping service or supplier API before it responds, it can only be as fast as that service. The fix might be calling the service in the background, caching its responses where that is safe, or setting a sensible timeout. Our guide to API integration covers how to handle slow and failed requests between systems.

Long-running work inside the request

Generating a large report, resizing uploaded images or sending hundreds of emails while the user's browser waits can cause timeouts, particularly when several people do it at once. This work usually belongs in a background job.

Common fixes and their trade-offs

Each of the common fixes has a trade-off, and a good proposal should mention it.

Caching stores the result of slow work so it can be reused. It can make a large difference to pages and reports that many people request in the same form. The costs are that users may see slightly out-of-date information, someone has to decide when cached data is refreshed, and caching per-user or per-customer data carelessly can show one person another person's information.

Pagination loads records in batches instead of all at once, which keeps list screens fast as data grows. The screen still needs suitable navigation, whether page controls or loading more as the user scrolls, along with search, filters and exports that work across all the records. Totals and summaries may need separate handling.

Background processing moves slow work out of the user's request. The application can confirm that the job has been queued and show its progress while it runs ("your report is being prepared"). How long it takes still depends on the queue and the workload, and failed jobs need to be retried or reported, which adds some complexity.

Infrastructure changes include a larger server, a separate database server or a content delivery network (CDN) that serves files from locations closer to users. Google's guidance recommends a CDN to reduce server response time for public pages. Bigger servers increase monthly costs, and they can hide an inefficient query instead of fixing it. They make most sense when measurements show the server is genuinely at capacity after the obvious inefficiencies have been dealt with.

Where frameworks fit

The framework your application uses affects what is possible and how much work certain improvements take, but changing frameworks does not make an application faster by itself. The same problems described above can occur in any of them.

React is a library for building user interfaces. On its own, it leaves decisions such as routing, data fetching and how pages are rendered to the tools and frameworks around it. React's own documentation warns that code splitting done badly can make loading slower, and that data fetched inside components can create waterfalls.

Next.js is a framework built on React that adds server rendering, static generation and routing. In Next.js's App Router, pages and layouts are Server Components by default, which can reduce the JavaScript sent to the browser and let content start appearing sooner. The benefit depends on how it is used: marking a component as client-side brings everything it imports into the browser bundle, so careless use can cancel out the advantage.

Vue is a progressive framework that can run entirely in the browser or with server rendering through frameworks built on it. Its server-side rendering guide is candid about the trade-offs: rendering pages on the server for each request adds hosting and server requirements, as well as some development constraints. It also notes that for an internal dashboard, where a few hundred extra milliseconds on first load do not matter much, server rendering would be overkill.

That last point applies across frameworks. Server rendering mainly helps how quickly content first appears, which matters for public pages and customers on slow phones. It does little for a slow report or a laggy data table.

TypeScript and CSS frameworks such as Tailwind come up in these discussions too. They affect how code is written and maintained, and neither is a performance fix in itself.

When a rebuild is justified, we can rebuild with a framework such as Next.js and choose the rendering approach page by page. That choice should follow from the measurements, never the other way round.

Targeted fixes or a rebuild?

Targeted improvements are usually enough when the causes can be identified and are concentrated in a few places: a handful of slow queries, too many apps or scripts, oversized images, one report doing too much work. The Shopify store above is an example: much of the unnecessary work came from what had been added to the store, so removing it was the right starting point.

A larger refactor or rebuild becomes worth discussing when the evidence points that way, for example:

  • the same performance problem appears across many screens because of how the application is structured, so fixing it in one place does not fix it elsewhere
  • targeted fixes have been made and measured, and the important workflows are still too slow
  • the platform or codebase makes the necessary changes impractical or unusually expensive
  • performance is one of several problems, alongside outdated dependencies, security concerns or code nobody can safely change

If a developer recommends a rebuild for performance reasons, ask to see the measurements behind it, which causes they found, why those causes cannot be fixed in the current system and how the new version will be measured against the old one. "The framework is outdated" is not a measurement. Our guide to custom web application development covers the early structural decisions that are hardest to change later, and our maintenance cost guide explains what taking over an existing application involves.

We advise fixing or rebuilding based on which gives the client better value over the long term. That depends on how much has already been invested, how well the current system works apart from its speed and what the business needs from it next.

Prioritise by workflow, then measure again

Not every slow page deserves the same attention. Rank the problems by how much they affect important work: the checkout, the booking form, the screen staff use all day, the report that management needs every morning. A slow settings page used twice a year can wait.

After each change, measure the same workflow under comparable conditions: the same device and network settings, similar amounts of data, a similar cache state and, for server-side work, a similar time of day. Where possible, change one thing at a time so you know what made the difference. Field data takes time to catch up. Google's real-user data in PageSpeed Insights covers a rolling 28-day period, so improvements appear there gradually.

Questions to ask about a proposed performance fix

  • Which workflow is slow, and how was it measured?
  • What is the cause, and what evidence points to it?
  • What will the change do, and what are its trade-offs?
  • How will we measure the result, and under what conditions?
  • If a rebuild is proposed, why can the cause not be fixed in the current system?

Clear answers to these show the developer has found a cause before proposing a cure, whether the cure is a small fix or a new framework.

Frequently asked questions

Should I leave Shopify or WordPress because my site is slow?

Not before finding out why it is slow, as the Shopify example above shows. A move makes more sense if the platform cannot support what your business needs, with speed as one factor among several.

Why does PageSpeed Insights show different scores each time?

The lab score comes from a single simulated test, which varies with server response and network conditions at that moment. Run it several times and look at the trend. Where field data is available, it gives a more stable picture of what real users experience.

Is Your Application Slower Than It Should Be?

If pages take too long to load, screens lag or reports keep timing out, the first step is finding out why, before paying for a rebuild that may not address the cause.

retroXpect can review your existing website or web application, investigate the slowdown and propose appropriate improvements, as we did by clearing out unnecessary apps on a client's Shopify store. Where the evidence shows a rebuild is the better long-term value, we build custom web applications with a framework such as Next.js. We also take over existing systems and look after them on maintenance plans from S$500 per month. Message us on WhatsApp with what feels slow and which screens or tasks are affected, and we will suggest where to start.

Author
Founder and CEO retroXpect, Jackson Neo

Jackson Neo

Founder & CEO

Jackson Neo is the Founder and CEO of retroXpect. He works with businesses to plan and deliver websites, custom web applications and digital solutions.

Approver
Founder & CTO retroXpect, Ryan Aai

Ryan Aai

Founder & CTO

Ryan Aai is the Founder and CTO of retroXpect, where he leads technical development, system architecture and project delivery.

Ready to Start Your Project?

Let's discuss your requirements and create a solution that drives your business forward.

Get Free Consultation