Skip to content

Web performance optimization

Next.js Performance Engineering

Core Web Vitals work on existing Next.js applications - measured against field data, fixed at the architectural cause, and defended in CI so the numbers stay fixed.

Performance work has a failure mode: a team spends a sprint on optimisation, the score jumps, and six weeks later it is back where it started. Nothing was wrong with the fixes. What was missing was a mechanism to keep them.

How an engagement runs

Measure first, from the field. We begin with Chrome UX Report data and your RUM, segmented by device class and route template. A p75 LCP of 3.4s on mobile product pages is an actionable statement; "our Lighthouse score is 62" is not.

Find the cause, not the symptom. A slow LCP is a rendering decision, a font strategy, an image pipeline or a blocking third party. A poor INP is almost always the size and shape of the JavaScript that hydrates above the fold. We trace each metric to the specific commit-level decision that produced it.

Fix at the architectural level. Moving a component across the server boundary, removing a client-side data fetch that should have been a server render, replacing a 300KB date library, splitting a route that ships the entire admin bundle to anonymous visitors. These are the changes that hold.

Defend the result. Every engagement ends with a performance budget enforced in CI. A pull request that pushes the route bundle past its ceiling fails the check. The budget is the deliverable; the score is a side effect.

Why the score comes back

Because a score is an outcome and nobody owns an outcome. A budget is a number in a file, checked by a machine, on every pull request, and it fails the build of whoever exceeded it while they still remember what they changed.

That difference is the whole reason the second engagement usually does not happen. Optimisation without a budget is a loan against the next quarter: the same component gets a use client directive it does not need, the same library gets imported at the top level, and the regression arrives one reasonable commit at a time from people who had no way of knowing.

The budget has to measure the right thing to work. A ceiling on the total build output tells you nothing, because the build contains code no route loads. What we set is a ceiling per route on the gzipped JavaScript that route's HTML actually requests - which is the number a visitor pays.

Where the time actually goes

Across the engagements we run, the causes cluster:

A client boundary drawn too high. One directive on a layout ships that layout and everything beneath it to every visitor on every route below. It is the single most common cause of a poor INP in a Next.js application, and it is usually one line. Where the boundary belongs.

An image pipeline that is optimised everywhere except the one that matters. The LCP image lazy-loaded, unsized, or served through a transform that adds 300ms before the first byte. What that costs, and the fix.

A route that became dynamic without anybody deciding it should. One cookies() call in a shared component opts every route beneath it out of static rendering, and the CDN stops answering. The page did not get slower because of the code in it; it got slower because it stopped being cached.

Third parties loaded as though they were free. A tag manager that pulls in four more scripts, a chat widget that hydrates before the content, a consent banner blocking the render it was supposed to gate. These are not application code, which is exactly why nobody profiles them.

Fonts that block the text they are for. A self-hosted font without font-display, or three weights loaded where one is used above the fold.

What we do not do

We do not optimise against a lab score you chose in advance. If your field data says visitors are fine and a tool says 62, the honest answer is that the tool is measuring a device and a network your audience does not have, and we will tell you that rather than selling a sprint.

We also do not work around a cause we cannot fix by making something else faster to compensate. If the LCP problem is a third party your marketing team requires, the finding says so, and the decision about that trade-off belongs to you rather than being buried in a summary.

What you receive

A prioritised findings document with each issue traced to its cause and sized by effort, the implemented fixes as reviewable pull requests, the CI budget configuration, and a before/after comparison against field data once the change has been live long enough to move the 28-day window.

If the architecture itself is the ceiling - and on some applications it is - that is in the findings too, with the cost of the alternative next to it. That conversation belongs at the start of an engagement rather than at the end of one.

Scope and terms

Engagement model
Fixed scope, agreed in writing before work starts. Not a day rate against an open backlog.
Price and timeline
Both are set per project, once the scope is. Quoted together, before anything is built.
What we need from you
One person who can approve decisions, and access to your repository and issue tracker.
Not included
Anything outside the agreed scope. It becomes its own scope rather than a variation order.
Third-party costs
Hosting, licences, API fees and SaaS subscriptions are contracted and paid by you.
Invoicing
Codefacture Yazılım A.Ş., Türkiye. EUR, USD or GBP by bank transfer, with no Turkish VAT on exported services.

Frequently asked questions

Do you work from Lighthouse scores?
Not as the primary signal. Lighthouse is a lab tool and it is useful for reproducing a problem, but ranking and revenue follow field data. We start with Chrome UX Report and your real-user monitoring, then use the lab to isolate causes.
What if the problem is our CMS or our third-party scripts?
Then that is the finding. A large share of LCP and INP regressions we trace end at a tag manager, a chat widget or an unoptimised media pipeline rather than at application code. We report the cause we find, not the one that is convenient.
How is the target set?
Against your field data, agreed before the work starts. We tell you at that point whether the target is reachable inside the current architecture - and where it is not, the honest answer is a rebuild of the affected route, which you hear then rather than at the end.
How long before the numbers move?
The fixes land within the engagement; the field data follows on its own schedule. Chrome UX Report is a 28-day rolling window, so a change deployed today is fully reflected about a month later. Anyone promising a field-data improvement next week is quoting you a lab score.
We have no real-user monitoring. Can you still work?
Yes. Chrome UX Report covers any origin with enough traffic and costs nothing to query, which is usually enough to start. Where the origin is too small to appear there, installing basic field measurement is the first deliverable - optimising against lab numbers alone is how teams fix things that were never slow for real visitors.
Call us+1 848 272 7583WhatsApp+90 850 308 5436Emailinfo@codefacture.comContact page