
A seven-year-old web application has become noticeably slower.
Customers wait too long for dashboards to appear, larger accounts experience sluggish searches, and users occasionally click buttons twice because the interface takes too long to respond. Inside the company, the explanation starts to sound inevitable:
The application is old. We probably need to rebuild it.
Then the team measures what is actually happening.
The initial page downloads far more JavaScript than most users need. A dashboard makes eleven API requests before it becomes useful. One database query accounts for most of the delay experienced by larger customers, while a third-party analytics script occupies the browser's main thread at exactly the wrong time.
None of those problems requires rebuilding the application.
They require removing unnecessary work from the system that already exists.
That distinction matters because poor web application performance is not, by itself, evidence that the architecture needs to be replaced. Existing applications often contain years of accumulated performance cost—larger bundles, additional API calls, growing data, third-party scripts and features added to once-simple workflows. A targeted optimization program can frequently address those costs without taking on the expense and risk of rewriting a functioning product.
For Levelworks, this is an important part of Performant App Health. The goal is not to make an aging application look technically modern for its own sake. It is to keep important user journeys responsive as the application evolves.
A rebuild is an architectural answer.
Before considering an architectural answer, establish whether the problem is architectural.
Begin with actual user experience rather than server specifications.
For web applications, Google's Core Web Vitals provide a useful starting point. The current metrics cover loading through Largest Contentful Paint (LCP), responsiveness through Interaction to Next Paint (INP), and visual stability through Cumulative Layout Shift (CLS). Google currently recommends LCP of 2.5 seconds or less, INP of 200 milliseconds or less, and CLS of 0.1 or less at the 75th percentile of visits.
Those metrics do not tell you everything about a business application, so pair them with workflow measurements such as:
Segment results where useful by device, browser, geography, customer size or application version.
That last point can change the investigation completely. An application may appear acceptable overall while customers with large datasets or older mobile devices experience severe delays.
Google also distinguishes field data from laboratory measurement: development tools are useful for diagnosing problems before release, but only real-user data captures the full range of production devices, networks and interactions.
[Internal Link: “Why Is My App Slow? 10 Common Causes of Poor Application Performance”]
One of the fastest ways to improve an existing web application is often to stop making the browser load, parse and execute work that is not immediately necessary.
A mature application may ship code for:
even though the user initially needs only the dashboard.
That makes the first load pay for functionality that might never be used in that session.
The browser's critical rendering path describes the work required to turn HTML, CSS and JavaScript into visible pixels. MDN recommends reducing critical resources, deferring non-critical work and controlling resource priority so the browser can render useful content sooner. MDN: Critical Rendering Path
Useful improvements can include:
These are generally evolutionary changes. They improve how the existing application is delivered rather than requiring a new frontend architecture.
Web applications often load resources simply because they exist somewhere on the page.
Images far below the viewport, embedded media, complex widgets and code for unopened sections can all compete with content the user is actually waiting for.
MDN's lazy-loading guidance describes lazy loading as treating non-critical resources as deferred work so they do not unnecessarily lengthen the critical rendering path.
Good candidates include:
There is an important exception: do not lazily load something the user needs immediately merely because lazy loading sounds like a performance best practice.
The objective is to move non-essential initial work later, not to delay useful content.
JavaScript performance is one area where older web applications can accumulate substantial overhead.
Each script may individually appear reasonable. Over several years, however, teams add:
The browser must download, parse, compile and execute much of that code.
Chrome's performance guidance notes that JavaScript creates several kinds of cost: network transfer, parsing and compilation, execution on the main thread, and memory usage. Its recommendations include code splitting, removing unused code, and minifying and compressing what remains. Chrome for Developers: Reduce JavaScript Execution Time
Start by identifying the largest contributors rather than attempting a framework migration.
Ask:
Removing 300 KB of unnecessary JavaScript can be much less risky than rebuilding an entire frontend to achieve the same user-facing improvement.
Loading speed is only part of web performance.
An application can appear quickly and then feel sluggish when the user interacts with it.
The problem may be long-running JavaScript work blocking the browser's main thread.
Google's current INP optimization guidance specifically points teams toward long tasks, script evaluation, rendering complexity and large DOM updates when interactions respond slowly.
Common examples include:
Improvements may include reducing the amount of work, breaking larger tasks into smaller units, limiting unnecessary rerenders, virtualizing very large lists or moving suitable computation away from the main thread.
Again, none of these necessarily implies that the whole frontend needs replacing.
A few badly behaved interactions can make an otherwise sound web application feel much older than it really is.
Many web applications become slower because a single screen gradually acquires more API calls.
A dashboard might begin with:
GET /user
GET /account
GET /permissions
GET /projects
GET /notifications
GET /usage
GET /billing
GET /recommendations
Some requests can happen concurrently, but every additional round trip creates network and server work.
Before redesigning services, inspect whether the frontend is:
Sometimes one carefully designed endpoint or consolidated query can remove several network round trips.
In other cases, independent requests can simply execute concurrently.
The correct decision depends on the application, but the principle remains:
Do not rebuild the backend until you know whether the existing backend is slow or the frontend is simply asking it to do too much.
Older applications often contain code that engineers would design differently today.
That does not make all of it worth rewriting.
Use traces and profiling to identify the functions, endpoints or services responsible for meaningful latency.
Suppose one request takes 2.4 seconds:
Work
Time
Request processing
120 ms
Database
1,650 ms
External service
470 ms
Serialization/other
160 ms
Refactoring the controller may make the code cleaner without materially improving the user's experience.
Focus on the dominant delay.
Backend improvements might involve:
This keeps performance work proportional: modernize the parts creating measurable cost rather than rewriting large areas simply because they are old.
Growing databases are a frequent source of performance decline in applications that once felt fast.
The application code may not have changed significantly; the amount of data has.
Common opportunities include:
If one query dominates dashboard latency, fixing that query may produce more value than a much larger application rewrite.
Database optimization should still be evidence-led. Inspect slow-query data and execution plans rather than adding indexes indiscriminately.
The important point in the context of an existing web app is that data-access problems are often local enough to correct without replacing the application architecture around them.
Caching is particularly useful when the application repeatedly performs expensive work whose result can be safely reused.
Potential candidates include:
AWS's caching guidance notes that caching can improve read latency and throughput while reducing work against underlying systems, but it also warns against caching rapidly changing information without considering consistency or failing to monitor whether the cache is actually effective.
Caching works best when you can answer:
Adding Redis because "fast applications use caching" is not a performance strategy.
[Internal Link: “Caching Explained: When It Makes Your App Faster and When It Doesn’t”]
Not every performance improvement needs an application-code change.
CSS, JavaScript, images, fonts and other cacheable assets can often be served through a content delivery network.
Cloudflare's explanation of CDN performance notes that CDNs reduce latency partly by serving cached content geographically closer to users, reducing the distance requests need to travel to an origin server.
For globally distributed users, delivery architecture can therefore affect performance even when the application code itself is efficient.
Also review:
These are often comparatively low-risk improvements because they optimize how existing application assets reach users rather than changing business behaviour.
Images can easily become some of the largest resources on a web page.
Before changing the application layout, check whether it is sending images at much higher resolutions than the interface displays.
Useful improvements include:
Fonts deserve similar attention. An application may download several font families and weights before displaying its first useful screen even though only a subset is initially needed.
These changes are not architecturally exciting.
That is precisely why they are useful.
Performance projects often produce better results by removing obvious waste than by introducing sophisticated new systems.
Third-party code can become a hidden performance tax.
Analytics, advertising, chat, consent management, session replay and experimentation tools often execute inside the same browser experience as your own application.
That means their cost becomes your user's cost.
Audit them periodically:
If INP is poor, third-party JavaScript deserves particular attention because main-thread work can delay responses to user interactions. Google's INP guidance explicitly identifies JavaScript execution and long tasks as important contributors to poor responsiveness.
Removing one unnecessary third-party script may sometimes outperform weeks of fine-grained optimization elsewhere.
Not every operation can become instantaneous.
A complex report might genuinely require several seconds.
In those cases, the interface should communicate progress rather than appearing frozen.
Depending on the workflow, that may mean:
Perceived performance should not become a way of hiding genuinely poor performance, but good interaction design prevents unavoidable processing time from feeling like a broken application.
The distinction matters: first remove unnecessary waiting, then design honestly around the waiting that remains.
Once performance data is available, rank improvements by expected user impact rather than architectural attractiveness.
For example:
Opportunity
Expected impact
Effort
Rebuild required?
Remove unused JS from dashboard
High
Low–Medium
No
Fix slow account query
Very high
Medium
No
Lazy-load reporting module
Medium–High
Low
No
CDN/cache static assets
Medium
Low
No
Replace entire frontend framework
Uncertain
Very high
Yes
This changes the conversation.
Instead of asking:
Should we rebuild the application because it feels slow?
ask:
Which measurable performance problems cannot reasonably be corrected inside the existing system?
That is a much higher bar.
“Do not rebuild first” does not mean “never rebuild.”
A deeper architectural intervention may eventually be justified if performance constraints are embedded throughout the design and every improvement requires disproportionately risky work.
Warning signs can include:
Even then, profiling remains useful because it tells you exactly what the future architecture needs to solve.
Do not use a rebuild to escape uncertainty.
Understand the existing constraints first.
For most existing web applications, a practical sequence is:
Collect real-user performance, API latency and application traces. Identify the workflows producing the most user impact.
Eliminate unused assets, unnecessary requests, redundant calculations and obsolete third-party code.
Address the specific JavaScript, backend, database or dependency work responsible for most latency.
Apply appropriate caching, compression, lazy loading and CDN delivery.
Check slower devices, realistic datasets and meaningful customer segments rather than optimizing only the developer environment.
Establish measurements or performance budgets so new features do not gradually reintroduce the same problems.
This is usually far less disruptive than rebuilding the product while still attacking the performance issues users actually experience.
[Internal Link: “Application Performance Optimization: A Practical Guide”]
Rebuilding can be attractive because it creates the impression that years of accumulated problems can be replaced with a clean slate.
Performance does not usually work that neatly.
A newly rebuilt application can still send too much JavaScript, make too many API requests, execute inefficient queries or depend heavily on third-party services. A well-maintained older application can perform extremely well when its critical paths are understood and optimized deliberately.
For Levelworks, that is an important part of maintaining Performant App Health. Performance work should make the application users already depend on measurably better while preserving the business functionality and knowledge already invested in it.
The strongest starting point is therefore not:
“What technology should we rebuild this with?”
It is:
“What is making this application slow today, and how much of that can we remove without replacing what already works?”
Very often, that second question leads to a faster—and considerably less risky—answer.