Finding the real bottleneck before fixing anything
Lab data and field data answer different questions
A lab test, such as Lighthouse or WebPageTest, loads one page on one simulated device. It is repeatable, which makes it the right tool for diagnosing and for comparing before and after. Field data is collected from real visitors in real browsers. Google's Core Web Vitals assessment uses field data, taken at the 75th percentile of page loads over a rolling 28 days, so a fix made today takes weeks to show fully in Search Console. We use both: field data to choose which pages and metrics matter, lab data to find the cause, then field data again to confirm. A perfect lab score with poor field data means the test is not seeing what your visitors see.
What usually sits behind each metric
Largest Contentful Paint is mostly about the path to one element, often the hero image or headline. Slow server response, render-blocking CSS, a lazy-loaded hero and late-discovered images are the usual culprits. Interaction to Next Paint measures how quickly the page reacts to a tap or key press, and it suffers when heavy JavaScript occupies the main thread: large frameworks hydrating, tag managers, sliders, chat widgets. Cumulative Layout Shift comes from things that arrive late without reserved space, such as images without dimensions, ads, cookie banners and web fonts.
Caching is a design question
Turning on a cache plugin is easy. Deciding what may be cached, for whom and until when is the real work. Public pages can be served whole from a page cache or CDN. Logged-in pages cannot, so we cache the expensive pieces instead: query results and computed values in an object cache such as Redis, fragments of a page that are the same for everyone, API responses with short lifetimes. Every cached item needs a rule for when it is cleared, or you trade a slow site for a wrong one. On stores built with WooCommerce, cart and checkout must stay out of the page cache entirely.
The database and the code
When server response is slow we profile real requests instead of guessing. The pattern repeats: a query inside a loop that runs once per row, a missing index on a column used in every filter, a settings table loading megabytes on each request, a report that sums a year of records on demand. Fixes range from one index to restructuring how a screen loads its data, and in older systems they overlap with legacy PHP modernization.
Budgets keep the gains
Performance decays one plugin and one marketing tag at a time. We finish by setting a budget per template: maximum page weight, script size, request count and target readings for each vital. Field monitoring reports against it, and a new feature that breaks the budget is discussed before release. Keeping to it is ongoing work that fits naturally into a maintenance retainer.