Home / Articles / Website Performance
Website Performance

Slow Websites Are Not Always Due to Cache: How to Identify Bottlenecks from Browser to Database

Speeding up a website does not mean turning on all cache features or upgrading server specifications. First, identify the bottleneck—whether it's in the browser, network, PHP-FPM, or database queries—then fix the most problematic part.

Website Lambat Tidak Selalu Salah Cache: Cara Menemukan Bottleneck dari Browser sampai Database

Slow websites often feel like a single issue, but the causes can exist across multiple layers simultaneously. A page may wait too long for the server, download large images, run too much JavaScript, or get stuck fetching data from the database.

This is why optimizations that focus solely on Lighthouse scores are often insufficient. Real visitors use different devices, networks, and locations. Field data and local testing can yield different results, especially when pages are affected by cache, personalization, or user interactions.

This article discusses how to sequentially trace performance issues, so we don't guess or change servers before knowing the source of the problem.

Start with symptoms, not solutions

Before changing configurations, first determine what is actually slow.

  • Old pages start to appear: usually related to server response time, connection, or backend processes.
  • Main content appears late: check the hero image, fonts, CSS, and elements that contribute to Largest Contentful Paint (LCP).
  • Buttons feel unresponsive: check JavaScript and long tasks that block the main thread.
  • Pages shift while loading: check the size of images, ads, embeds, or dynamic components that do not have space reserved from the start.
  • Only certain pages are slow: suspect queries, templates, or plugins specific to those pages.

Core Web Vitals help categorize these symptoms. Common targets are a maximum LCP of 2.5 seconds, Interaction to Next Paint (INP) of 200 milliseconds, and a maximum Cumulative Layout Shift (CLS) of 0.1 at the 75th percentile. These numbers should be read as indicators of user experience, not as standalone test scores. Web Vitals documentation explains how these metrics are used.

Differentiate server time from browser time

A practical first step is to look at the waterfall in Chrome DevTools or WebPageTest. The waterfall shows the sequence of requests: DNS, connection, initial HTML response, CSS, JavaScript, images, and other requests.

If the HTML document only receives the first byte after a long time, the problem is likely in the backend or network. This metric is known as Time to First Byte (TTFB), which is the time until the browser receives the first byte from the server.

Conversely, if the HTML is fast but the page only feels ready after many assets have finished loading, focus your checks on image sizes, fonts, CSS, JavaScript, and third-party services. A page can have a good TTFB but still be slow because the browser has too much to process.

Check PHP-FPM before adding servers

In PHP applications, PHP-FPM is responsible for managing the processes that handle requests. One important setting is pm.max_children, which is the limit on the number of requests that can be served simultaneously. A value that is too low can cause requests to queue up. A value that is too high can consume RAM and cause the server to swap.

The official PHP documentation explains that the static, dynamic, and ondemand modes have different ways of creating worker processes. Therefore, do not copy configurations from other servers without calculating your own machine's capacity. PHP-FPM configuration reference can be a starting point.

What needs to be observed is not just the configuration numbers, but also the symptoms:

  • Does the number of workers often reach the maximum limit?
  • Does the wait time increase when traffic rises?
  • Is RAM usage nearing full?
  • Are PHP processes spending a lot of time on queries or external APIs?

If workers are full due to slow database queries, increasing pm.max_children will only add to the job queue. Fix the root cause first.

Use the database as a suspect that can be proven

Fast queries on small tables may not remain fast as data grows. To check the execution plan, use EXPLAIN. In MySQL 8.0.18 and later versions, EXPLAIN ANALYZE can run the query and display actual time, row counts, and the number of iterations for each part of the execution plan.

EXPLAIN ANALYZE
SELECT id, title
FROM articles
WHERE status = 'published'
ORDER BY published_at DESC
LIMIT 20;

Pay attention to whether the database reads significantly more rows than it returns, performs large sorts, or does not use appropriate indexes. MySQL documentation explains the difference between estimates in EXPLAIN and actual information from EXPLAIN ANALYZE. See MySQL EXPLAIN reference.

Reasonable improvements could include composite indexes, reducing the columns fetched, more efficient pagination, or breaking down overly large queries. However, additional indexes also come with costs: writing data can become heavier and storage size increases.

Optimize the most visible elements

If the main issue is with LCP, find out which element is the LCP. This element could be an image, text block, video poster, or background image. Hero images are often suspects because they are large and are only requested after CSS or JavaScript has finished running.

Some steps that are usually safe to try:

  1. Use image dimensions close to the display size, not the original photo in very large size.
  2. Choose modern formats if the site's workflow supports them.
  3. Do not lazy-load the main images that are immediately visible on the screen.
  4. Ensure fonts do not hold up the display of the main text for too long.
  5. Reduce redirects and requests to unnecessary third-party domains.

For CLS, set image sizes and component spaces before content loads. The goal is simple: the browser knows the space to reserve from the start, so text or buttons do not suddenly get pushed down.

Excessively busy JavaScript also makes websites feel slow

A website may finish downloading but still feel uncomfortable to use because the browser is busy executing JavaScript. Menus, searches, filters, and checkout buttons will feel delayed if the main thread is blocked by long tasks.

Start by removing scripts that are no longer in use, deferring non-critical scripts, and loading analytics services asynchronously. Avoid installing many widgets just because they are available. Each widget brings JavaScript, connections, and potential additional work in the browser.

INP measures the page's response to user interactions. Therefore, testing should not just load the page and stop. Try opening menus, typing in search fields, using filters, and clicking main buttons. Field measurements are better at capturing issues that arise only after user interactions.

Order of fixes that can be done now

  1. Record the page, device, location, and conditions when the slowness occurs.
  2. Compare field data with local testing using PageSpeed Insights or DevTools.
  3. Check TTFB and waterfall to separate server issues from browser issues.
  4. If TTFB is high, check PHP-FPM, database queries, page cache, and external APIs.
  5. If TTFB is good but LCP is poor, check the main images, CSS, fonts, and asset loading order.
  6. If interactions are slow, record activity in DevTools and look for long JavaScript tasks.
  7. Test one change at a time, then compare results before and after.

Good performance is not the result of a single “optimize” button. It usually comes from accurate diagnosis, measurable small changes, and monitoring after release.

What does this mean for us?

Do not immediately conclude that the website needs a new CDN, a more expensive server, or additional cache plugins. The problem may simply be a hero image that is too large, queries without indexes, PHP workers that are always full, or unnecessary third-party JavaScript.

Start from the path taken by a single request: the browser requests the page, the server runs the application, the application fetches data, then the browser renders and responds to interactions. With that order, optimization becomes a reasonable investigative task—not a race to chase scores.

Sources & further reading

Explore also

– Rio Yotto @rioyotto