Skip to content

Why Is My Web App Slow? 10 Causes and How to Fix Them

Why is my web app slow? The 10 most common causes, from N+1 queries and missing indexes to heavy images and blocking jobs, and how to fix each one.

By

Freelance full-stack developer

Published
Reading time
14 min
In this post9

The usual answer to "why is my web app slow?" is not that the server is too small. Most slow web apps suffer from a handful of specific bottlenecks: too many database queries, missing indexes and caching, work that runs while the user waits, or heavy images and scripts in the browser. Nearly all of them can be found with the right tools and fixed without a rebuild.

I sell maintenance and development work on existing web apps, so keep that bias in mind. I've tried to be clear about what you can check yourself, and when a developer like me is the wrong call.

The short answer: match the symptom to the cause

Start with what you actually see. Most slowdowns have a recognizable signature.

What you noticeLikely causeUsual fix
Lists get slower as they grow1. N+1 queries, 3. loading too much dataLoad related data up front, paginate
Search and filters drag on large tables2. Missing indexesIndex the columns you filter and sort on
Dashboards and reports are slow for everyone4. No cachingStore the result and reuse it
A button spins for several seconds5. Heavy work inside the requestMove it to a background queue
Slow only when another system is involved6. Third-party API callsTimeouts, queues and a local copy
The page paints slowly, worst on mobile7. Oversized images, 9. uncached static filesResize, modern formats, compression
The page looks ready but ignores clicks8. Too much JavaScriptShip less code, cut third-party tags
Everything is a little slow, all the time10. Outdated setup or wrong hostingCurrent PHP, production settings, closer servers

My rule of thumb: if the server is slow to send anything back, the cause is usually somewhere in 1-6 or 10. If the first response is fast but the page still feels heavy, look at 7-9.

Speed is easier to plan for than to bolt on later, which is why it shows up early in my guide to the software development process from idea to launch.

First, find out where the time goes

Before anyone touches the code, you need to know whether the delay is on the server or in the browser. Otherwise you can end up paying to compress images when the real problem is a four-second database query.

In the browser. Run your most important public pages through Google's PageSpeed Insights. Google's targets are that the largest element appears within 2.5 seconds, the page responds to a click within 200 milliseconds, and the layout doesn't jump around while loading. These are the three Core Web Vitals, and according to Google's own guide to the metrics a page should hit them for at least 75% of visits. PageSpeed Insights can't log in, so for pages behind a login, use the Network tab in your browser's developer tools.

On the server. Time to First Byte (TTFB) is how long the browser waits before the server starts responding. Google rates 0.8 seconds or less as good. If your app is well above that, the server's work is the place to dig. A developer will use a profiler that lists every database query and how long it takes. I use Ray for this on Laravel projects, and Laravel Debugbar and Telescope are popular alternatives.

What you can do yourself is note which pages are slow, for whom and when. "The orders page is slow for admins on Monday mornings" is far more useful to a developer than "the app is slow".

Database causes

In web apps with users, orders and reports, the database is the most common bottleneck. These problems hide during development because test data is small, then surface months after launch once real data has piled up.

1. N+1 queries: hundreds of tiny lookups instead of one

Picture an orders list where every row shows the customer's name. The code fetches all orders in one query, then fetches each customer one by one. Laravel's own documentation uses 25 books and their authors as the example, where the loop runs 26 queries instead of 2. With 500 rows, that's 501.

Each query is fast on its own, so nobody notices on a staging server with ten orders. The fix is to load the related records up front in a single query, known as eager loading. It's usually a small change per page. Laravel can also be configured to throw an error during development whenever code lazy-loads a relationship, which catches new cases before they reach production.

2. Missing database indexes

A database index works like the index at the back of a book. Without one, the database has to read the whole table to find the rows you asked for, and the MySQL documentation is blunt that this gets more expensive the bigger the table grows.

The symptom is search, filtering and sorting that get a little slower every month. The fix is to add indexes on the columns you filter and sort by, such as customer, status and date. It takes some judgment, because every index makes writes slightly slower and uses disk space. In most web apps, though, tables are read far more often than they're written, and a missing index on a key column is one of the cheapest fixes on this list.

3. Loading more data than the page shows

A page that displays 25 customers but loads all 20,000 and sorts them in application code gets slower with every signup. The same goes for queries that pull every column, including large text fields, when the page only shows a name and an email, and for reports that add things up in code instead of letting the database do the math.

The fix is pagination, selecting only the columns you need, and letting the database count, sum and sort. Large exports and imports should run in chunks so they don't run out of memory halfway. None of this is hard, but someone has to go through the heaviest pages one at a time.

Backend causes

4. Nothing is cached

Caching means storing a result and reusing it instead of recalculating it every time. A dashboard showing monthly revenue doesn't need to scan every order each time someone opens it. The result can be stored for five minutes, an hour, or until a new order comes in.

The symptom is pages full of numbers, charts and stats that are slow for every user, even though the figures barely change. Caching works, but it has a cost: if the cache isn't cleared correctly, users see stale numbers. So you decide page by page how fresh the data needs to be. I usually start with the handful of pages that are opened most and are most expensive to compute, rather than caching everything.

5. Slow work happens while the user waits

When someone clicks "Send invoice" and the page spins for eight seconds, the app is often generating the PDF, sending the email and syncing with the accounting system before it replies. All of that can happen in the background. With a queue, the user gets an instant response and the job runs a moment later.

The same applies to bulk emails, file imports, image processing and syncing with other systems. Queues are built into Laravel, which is one of the reasons I use Laravel for most web apps. Queues do need monitoring, though. A stalled queue causes a quieter kind of failure: the email simply never arrives.

6. Waiting on third-party APIs

Many apps pull data from other services: payments, accounting, shipping or a CRM. If your page waits for Stripe, Xero or a shipping carrier every time it loads, your app can never be faster than theirs. And if their API is down, your page may hang for many seconds before giving up.

The fix combines three things: short timeouts so your app gives up in time, a local copy of data that doesn't change by the second, and moving calls that don't need to happen immediately onto the queue. Suspect this cause first if the app is only slow at certain times or in certain flows.

Frontend causes

Even with a fast server, a page can feel slow if the browser has too much to download and run. Mobile users on patchy connections feel it most.

7. Oversized images

A photo straight from a camera or a design file can easily be several megabytes. If it's displayed as a 300-pixel-wide card, the browser still downloads the whole file. It's one of the most common reasons a page paints slowly.

The fix is to resize images to the size they're displayed at and to use modern formats like WebP and AVIF. Tests cited in Google's guide to AVIF show significantly smaller files than JPEG. Images further down the page can wait until the user scrolls (lazy loading). If users upload their own images, the app should handle all of this automatically, because nobody will do it by hand.

8. Too much JavaScript and too many third-party tags

A page can look finished and still ignore your clicks. That usually means the browser is busy running JavaScript. The culprit is often the app's own code bundled into one large file for every page, or scripts from other vendors: chat widgets, analytics, ad pixels, video players and, in the EU, the consent banner that sits in front of all of them.

The fix is to split the code so each page only loads what it uses, remove libraries nobody needs anymore, and have an honest conversation about every third-party tag. The question isn't whether a script is useful, it's whether it's worth the speed it costs. On public pages, third-party tags are often a bigger drag than the app's own code.

9. Static files without compression or caching

Images, stylesheets, fonts and JavaScript rarely change. Yet many servers make the browser download them again on every visit, or send them uncompressed. That hurts returning users the most, and a web app is mostly returning users.

The fix lives in server configuration: gzip or Brotli compression, long cache lifetimes for files that get a new name when they change, and possibly a CDN, a network of servers that delivers files from a location close to the user. It's often one of the quickest wins here because it's a settings change, not a code change.

Infrastructure causes

10. An outdated setup or the wrong hosting

The last cause makes everything a bit slow, all the time. Typical examples are an old PHP version, an app running in debug mode in production, OPcache switched off (it keeps compiled PHP code in memory), and Laravel's config and route caching never being enabled. Newer PHP versions are generally faster and still receive security fixes.

Then there's hosting: cheap shared hosting where your app competes with many other sites, a single small server where the database, queue workers and web server fight over the same resources, or a server on the wrong side of the Atlantic. If most of your users are in Europe and the app runs in a US region, every request makes a long round trip. An EU region is usually faster for European users and makes GDPR conversations about where data lives simpler. Just change hosting after you've checked causes 1-9, or you'll move the same problem onto a more expensive server.

When more hardware, a rewrite or a developer isn't the answer

It's tempting to buy your way out of a slow app. Sometimes that's reasonable. Often it isn't.

A bigger server helps when the app genuinely lacks resources, for example because traffic has grown sharply. It won't fix a page that runs 500 queries or lacks an index. The bad code just runs a bit faster until your data catches up with the new server.

A rewrite or a move to microservices is rarely the answer to speed. The causes on this list show up in every framework and architecture, and splitting an app into many services adds network calls between them. My advice is that most projects should start as a monolith. If the code is so tangled that every fix creates two new bugs, though, slowness is a symptom of technical debt and should be treated as such. Not sure where your codebase stands? Check it against these signs of a healthy codebase.

A developer like me isn't always the right hire either:

  • If your site runs on Shopify, Wix or a WordPress theme with lots of plugins, find a specialist in that platform. Much of the speed depends on the platform's own limits.
  • If it's a SaaS tool you subscribe to, such as a booking system or a CRM, the vendor has to fix it. Send them specific examples with the page and the time.
  • If the app is only slow for one person or on one network, check their connection and browser before paying anyone.
  • If your key pages already meet Google's targets and nobody is complaining, your budget is usually better spent on new features.

Next steps: how to speed up your web app

  1. Pick the three to five pages that matter most to your users or your revenue. Measure those first, not the whole app.
  2. Measure them: PageSpeed Insights for public pages and time to first byte for pages behind the login. Write the numbers down so you can tell whether the fixes worked.
  3. Fix whatever gives the most for the least. An index or eager loading on a central page is often a small job with a big effect.
  4. Set up monitoring so you notice when a page slows down again. Speed is part of ongoing web application maintenance, not a one-off project.

If you'd like help finding and fixing the bottlenecks, my page on maintenance and development for existing web apps explains how I work. You deal directly with the person writing the code, I work from Denmark on Central European Time, and you'll get a reply within one business day.

Frequently asked questions

How much does it cost to make a slow web app faster?

It depends mostly on how many causes there are and how well the code is structured. A missing index or an N+1 query can often be fixed in a few hours once it's found. Finding it usually takes longer than fixing it. If the slowness comes from deep technical debt, it becomes a bigger project. Ask for a fixed-scope review of your most important pages first, so you know what you're paying for.

Does a slow web app hurt my Google rankings?

For public pages, speed can play a part. Google uses Core Web Vitals as one of many signals, but relevant content counts for more. Google can't see pages behind a login at all, so there speed is about your users, not search engines. For most web apps, the real cost of slowness is wasted time for staff and customers rather than lost rankings.

Why is my web app only slow some of the time?

When speed varies, the cause is usually something that happens at specific times. Common culprits are scheduled jobs running heavy reports, a queue backing up, a cache that has just expired, or a third-party API having a bad day. On shared hosting, other customers' traffic can slow you down too. Note the times it happens so a developer can match them against the server logs.

Is PHP too slow for a modern web app?

No, PHP is rarely the bottleneck in a typical business web app. Modern PHP with OPcache is fast enough for most workloads, and the causes on this list, like excess queries, missing caching and heavy pages, show up in Node, Python and Ruby apps too. Rewriting in another language usually repeats the same mistakes at a much higher price than fixing them where they are.