You want a 2.5 second largest contentful paint at the 75th percentile on mid-range Android over a typical mobile connection. Roughly how much JavaScript can you ship on the critical path, and which assumption dominates the error?
Show the full answer Hide the answer
The assumptions, stated
- The target. Google's published "good" threshold for largest contentful paint is 2.5 s, assessed at the 75th percentile of page loads - so the budget must hold for the slower three quarters of your users, not the median.
- The network. Lighthouse's simulated mobile profile uses roughly 1.6 Mbps throughput and 150 ms round-trip time, which is about 200 KB per second of transfer once compressed.
- The device. Parse, compile and execute on a mid-range Android phone runs on the order of 1 MB of uncompressed JavaScript per second of main-thread time, and execution of framework startup code can be worse than parsing.
The arithmetic
Budget: 2.5 s total, of which connection setup and the HTML round trip consume roughly 0.5 s before any asset is requested. That leaves about 2 s.
Split it: 1 s of transfer, 1 s of main-thread work.
- 1 s of transfer at 200 KB/s = 200 KB compressed.
- 200 KB compressed is roughly 600-700 KB uncompressed, which needs 0.6-0.7 s of parse, compile and execute - most of the main-thread second, before any of your own rendering runs.
So the order of magnitude is 150-200 KB compressed of JavaScript on the critical path, with everything else deferred. Pinterest's 2017 rebuild landed on roughly 150 KB for its core bundle, which is the same arithmetic reached empirically.
Which assumption dominates the error
The device, not the network. Network throughput varies by a factor of two or three across a realistic population; main-thread speed varies by a factor of five to ten between a current flagship and a three-year-old mid-range phone, and the slow end is where the 75th percentile lives. A budget derived from network speed alone will be met on paper and missed in the field.
The second-largest error is the split between transfer and execution. Framework startup, hydration and third-party scripts all land on the main thread, so a page that transfers quickly can still miss the target entirely.
What the number rules in and out
- Rules out: shipping a full component framework, a date library, an icon set and an analytics bundle before first paint. That is the budget spent with nothing rendered.
- Rules in: server rendering or static generation for the first view, with interactivity hydrated selectively afterwards.
- Rules in: a build-time budget check that fails the pipeline. A number nobody enforces is not a budget.
- Does not rule out a large application - it constrains what is on the critical path, which is a routing and code-splitting question rather than a total-size question.
When this estimate is the wrong basis
For an authenticated application with hour-long sessions, first-load cost is amortised and the binding constraint is interaction latency, not LCP. Optimising the initial bundle there buys almost nothing.
Equally, if your real users are on desktop over fibre - check the field data before assuming - the mobile profile is the wrong model and the budget derived from it will cost you features for no gain. Derive the budget from your own device and network distribution; borrow the method, not the number.