[{"data":1,"prerenderedAt":1437},["ShallowReactive",2],{"content:\u002Fframework-performance\u002Fnextjs-performance\u002Freducing-nextjs-first-load-javascript":3,"surroundings:\u002Fframework-performance\u002Fnextjs-performance\u002Freducing-nextjs-first-load-javascript":1428},{"id":4,"title":5,"body":6,"description":1409,"extension":1410,"meta":1411,"navigation":1421,"path":1422,"seo":1423,"stem":1426,"__hash__":1427},"content\u002Fframework-performance\u002Fnextjs-performance\u002Freducing-nextjs-first-load-javascript\u002Findex.md","Reducing Next.js First Load JavaScript",{"type":7,"value":8,"toc":1391},"minimark",[9,14,29,37,147,152,194,198,207,213,219,225,229,234,240,244,247,386,390,613,617,624,750,754,760,764,779,860,864,874,1179,1183,1186,1190,1220,1224,1230,1236,1248,1254,1258,1272,1281,1293,1302,1311,1320,1332,1341,1350,1354,1376,1381,1384,1387],[10,11,13],"h1",{"id":12},"how-to-reduce-nextjs-first-load-javascript","How to Reduce Next.js First Load JavaScript",[15,16,17,18,23,24,28],"p",{},"This guide is part of ",[19,20,22],"a",{"href":21},"\u002Fframework-performance\u002Fnextjs-performance\u002F","Next.js Performance",", within ",[19,25,27],{"href":26},"\u002Fframework-performance\u002F","Framework Performance",". \"First Load JS\" in Next.js build output is the compressed JavaScript a browser downloads for the first visit to a route: the shared framework and app chunks plus the route's own chunks. It is a strong predictor of hydration cost and early INP on mobile, where each 100KB of compressed JavaScript means roughly a third of a second or more of main-thread work.",[15,30,31,32,36],{},"First Load JS grows in predictable ways: a client component high in the tree (a layout or provider with ",[33,34,35],"code",{},"\"use client\"","), a large library imported where only a small part is used, a heavy widget included statically on every page, polyfills for old browsers, and analytics SDKs bundled instead of loaded as scripts. Each has a direct fix.",[15,38,39],{},[40,41,47,48,47,55,47,59,47,62,47,71,47,77,47,84,47,93,47,98,47,102,47,107,47,111,47,115,47,119,47,123,47,127,47,131,47,135,47,139,47,143,47],"svg",{"viewBox":42,"width":43,"role":44,"ariaLabel":45,"style":46},"0 0 760 225","100%","img","Bar chart of contributors to first-load JavaScript for a Next.js article route.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[49,50],"rect",{"className":51,"x":53,"y":53,"width":43,"height":43,"fill":54},[52],"svg-canvas","0","#ffffff",[56,57,58],"title",{},"Where First Load JS came from (article route, compressed)",[60,61,45],"desc",{},[49,63],{"x":64,"y":64,"width":65,"height":66,"rx":67,"fill":68,"stroke":69,"style":70},"1","758","223","10","none","currentColor","stroke-opacity:0.18",[72,73,58],"text",{"x":74,"y":75,"fill":69,"style":76},"28.0","34.0","font-size:16px;font-weight:700",[72,78,83],{"x":79,"y":80,"fill":69,"style":81,"textAnchor":82},"192.7","70.0","font-size:13px","end","React + Next.js runtime",[49,85],{"x":86,"y":87,"width":88,"height":89,"rx":90,"fill":91,"stroke":91,"style":92},"204.7","56.0","463.3","19","3","#0466c8","fill-opacity:0.55;stroke-opacity:0.9",[72,94,97],{"x":95,"y":80,"fill":69,"style":96},"674.0","font-size:12px;font-weight:600","88KB",[72,99,101],{"x":79,"y":100,"fill":69,"style":81,"textAnchor":82},"101.0","Client layout + providers",[49,103],{"x":86,"y":104,"width":105,"height":89,"rx":90,"fill":68,"stroke":69,"style":106},"87.0","284.3","fill-opacity:0.7;stroke-opacity:0.35",[72,108,110],{"x":109,"y":100,"fill":69,"style":96},"495.0","54KB",[72,112,114],{"x":79,"y":113,"fill":69,"style":81,"textAnchor":82},"132.0","Date and markdown libraries",[49,116],{"x":86,"y":117,"width":118,"height":89,"rx":90,"fill":68,"stroke":69,"style":106},"118.0","242.2",[72,120,122],{"x":121,"y":113,"fill":69,"style":96},"452.9","46KB",[72,124,126],{"x":79,"y":125,"fill":69,"style":81,"textAnchor":82},"163.0","Comments widget",[49,128],{"x":86,"y":129,"width":130,"height":89,"rx":90,"fill":68,"stroke":69,"style":106},"149.0","200.1",[72,132,134],{"x":133,"y":125,"fill":69,"style":96},"410.8","38KB",[72,136,138],{"x":79,"y":137,"fill":69,"style":81,"textAnchor":82},"194.0","Route code",[49,140],{"x":86,"y":141,"width":142,"height":89,"rx":90,"fill":91,"stroke":91,"style":92},"180.0","115.8",[72,144,146],{"x":145,"y":137,"fill":69,"style":96},"326.5","22KB",[148,149,151],"h2",{"id":150},"rapid-diagnosis","Rapid Diagnosis",[153,154,155,166,180,188],"ul",{},[156,157,158,165],"li",{},[159,160,161,162],"strong",{},"Run ",[33,163,164],{},"next build"," and read First Load JS per route.",[156,167,168,171,172,175,176,179],{},[159,169,170],{},"Run the bundle analyzer"," (",[33,173,174],{},"ANALYZE=true next build"," with ",[33,177,178],{},"@next\u002Fbundle-analyzer",") and inspect the client chunks.",[156,181,182,187],{},[159,183,184,185],{},"Search for ",[33,186,35],{}," in layouts, providers and shared components.",[156,189,190,193],{},[159,191,192],{},"List dependencies imported in client components"," and their sizes.",[148,195,197],{"id":196},"root-cause-analysis","Root Cause Analysis",[15,199,200,203,204,206],{},[159,201,202],{},"1. Client boundaries too high."," Everything below a ",[33,205,35],{}," boundary that is imported ships to the client.",[15,208,209,212],{},[159,210,211],{},"2. Heavy libraries in client code."," Date, markdown, syntax highlighting, charting and icon libraries.",[15,214,215,218],{},[159,216,217],{},"3. Statically imported widgets."," Comments, chat, maps and carousels included on every page load.",[15,220,221,224],{},[159,222,223],{},"4. Shared providers."," Global providers wrapping the app pull their dependencies into the shared chunk.",[148,226,228],{"id":227},"step-by-step-resolution","Step-by-Step Resolution",[230,231,233],"h3",{"id":232},"_1-move-client-boundaries-to-the-leaves","1. Move client boundaries to the leaves",[15,235,236,237,239],{},"Keep layouts, pages and content components as Server Components. Put ",[33,238,35],{}," only on small interactive components (buttons, forms, toggles), and pass data from the server as props.",[230,241,243],{"id":242},"_2-move-non-interactive-work-to-the-server","2. Move non-interactive work to the server",[15,245,246],{},"Format dates, render markdown and highlight code in Server Components, so those libraries never reach the client.",[248,249,254],"pre",{"className":250,"code":251,"language":252,"meta":253,"style":253},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F\u002F Server Component: markdown rendered on the server, no client cost.\nimport { marked } from 'marked';\nexport default async function Post({ slug }) {\n  const post = await getPost(slug);\n  return \u003Carticle dangerouslySetInnerHTML={{ __html: marked.parse(post.body) }} \u002F>;\n}\n\u002F\u002F trade-off: rendering untrusted markdown to HTML requires sanitisation; do it on\n\u002F\u002F the server once rather than in every visitor's browser.\n","javascript","",[33,255,256,265,286,312,334,368,374,380],{"__ignoreMap":253},[257,258,261],"span",{"class":259,"line":260},"line",1,[257,262,264],{"class":263},"sjfSM","\u002F\u002F Server Component: markdown rendered on the server, no client cost.\n",[257,266,268,272,276,279,283],{"class":259,"line":267},2,[257,269,271],{"class":270},"sPARh","import",[257,273,275],{"class":274},"saISM"," { marked } ",[257,277,278],{"class":270},"from",[257,280,282],{"class":281},"sZ8jY"," 'marked'",[257,284,285],{"class":274},";\n",[257,287,289,292,295,298,301,305,309],{"class":259,"line":288},3,[257,290,291],{"class":270},"export",[257,293,294],{"class":270}," default",[257,296,297],{"class":270}," async",[257,299,300],{"class":270}," function",[257,302,304],{"class":303},"smZ65"," Post",[257,306,308],{"class":307},"sQw3B","({ slug }) ",[257,310,311],{"class":274},"{\n",[257,313,315,318,322,325,328,331],{"class":259,"line":314},4,[257,316,317],{"class":270},"  const",[257,319,321],{"class":320},"sPXB4"," post",[257,323,324],{"class":270}," =",[257,326,327],{"class":270}," await",[257,329,330],{"class":303}," getPost",[257,332,333],{"class":274},"(slug);\n",[257,335,337,340,343,347,350,353,356,359,362,365],{"class":259,"line":336},5,[257,338,339],{"class":270},"  return",[257,341,342],{"class":274}," \u003C",[257,344,346],{"class":345},"sZBmE","article",[257,348,349],{"class":320}," dangerouslySetInnerHTML",[257,351,352],{"class":270},"={",[257,354,355],{"class":274},"{ __html: marked.",[257,357,358],{"class":303},"parse",[257,360,361],{"class":274},"(post.body) }",[257,363,364],{"class":270},"}",[257,366,367],{"class":274}," \u002F>;\n",[257,369,371],{"class":259,"line":370},6,[257,372,373],{"class":274},"}\n",[257,375,377],{"class":259,"line":376},7,[257,378,379],{"class":263},"\u002F\u002F trade-off: rendering untrusted markdown to HTML requires sanitisation; do it on\n",[257,381,383],{"class":259,"line":382},8,[257,384,385],{"class":263},"\u002F\u002F the server once rather than in every visitor's browser.\n",[230,387,389],{"id":388},"_3-defer-heavy-client-components","3. Defer heavy client components",[248,391,393],{"className":250,"code":392,"language":252,"meta":253,"style":253},"'use client';\nimport dynamic from 'next\u002Fdynamic';\nconst Comments = dynamic(() => import('.\u002FComments'), { loading: () => \u003Cdiv style={{ minHeight: 400 }} \u002F> });\nexport default function CommentsSection({ id }) {\n  const [show, setShow] = React.useState(false);\n  return show ? \u003CComments id={id} \u002F> : \u003Cbutton onClick={() => setShow(true)}>Show comments\u003C\u002Fbutton>;\n}\n\u002F\u002F trade-off: loading on click adds a short delay when the user asks for comments;\n\u002F\u002F load on visibility instead if most readers open them.\n",[33,394,395,402,416,479,495,531,598,602,607],{"__ignoreMap":253},[257,396,397,400],{"class":259,"line":260},[257,398,399],{"class":281},"'use client'",[257,401,285],{"class":274},[257,403,404,406,409,411,414],{"class":259,"line":267},[257,405,271],{"class":270},[257,407,408],{"class":274}," dynamic ",[257,410,278],{"class":270},[257,412,413],{"class":281}," 'next\u002Fdynamic'",[257,415,285],{"class":274},[257,417,418,421,424,426,429,432,435,438,441,444,447,450,453,455,457,460,463,465,468,471,474,476],{"class":259,"line":288},[257,419,420],{"class":270},"const",[257,422,423],{"class":320}," Comments",[257,425,324],{"class":270},[257,427,428],{"class":303}," dynamic",[257,430,431],{"class":274},"(() ",[257,433,434],{"class":270},"=>",[257,436,437],{"class":270}," import",[257,439,440],{"class":274},"(",[257,442,443],{"class":281},"'.\u002FComments'",[257,445,446],{"class":274},"), { ",[257,448,449],{"class":303},"loading",[257,451,452],{"class":274},": () ",[257,454,434],{"class":270},[257,456,342],{"class":274},[257,458,459],{"class":345},"div",[257,461,462],{"class":320}," style",[257,464,352],{"class":270},[257,466,467],{"class":274},"{ minHeight: ",[257,469,470],{"class":320},"400",[257,472,473],{"class":274}," }",[257,475,364],{"class":270},[257,477,478],{"class":274}," \u002F> });\n",[257,480,481,483,485,487,490,493],{"class":259,"line":314},[257,482,291],{"class":270},[257,484,294],{"class":270},[257,486,300],{"class":270},[257,488,489],{"class":303}," CommentsSection",[257,491,492],{"class":307},"({ id }) ",[257,494,311],{"class":274},[257,496,497,499,502,505,508,511,514,517,520,523,525,528],{"class":259,"line":336},[257,498,317],{"class":270},[257,500,501],{"class":274}," [",[257,503,504],{"class":320},"show",[257,506,507],{"class":274},", ",[257,509,510],{"class":320},"setShow",[257,512,513],{"class":274},"] ",[257,515,516],{"class":270},"=",[257,518,519],{"class":274}," React.",[257,521,522],{"class":303},"useState",[257,524,440],{"class":274},[257,526,527],{"class":320},"false",[257,529,530],{"class":274},");\n",[257,532,533,535,538,541,543,546,549,551,554,556,559,562,564,567,570,572,575,577,580,582,585,588,590,593,595],{"class":259,"line":370},[257,534,339],{"class":270},[257,536,537],{"class":274}," show ",[257,539,540],{"class":270},"?",[257,542,342],{"class":274},[257,544,545],{"class":345},"Comments",[257,547,548],{"class":320}," id",[257,550,352],{"class":270},[257,552,553],{"class":274},"id",[257,555,364],{"class":270},[257,557,558],{"class":274}," \u002F> ",[257,560,561],{"class":270},":",[257,563,342],{"class":274},[257,565,566],{"class":345},"button",[257,568,569],{"class":320}," onClick",[257,571,352],{"class":270},[257,573,574],{"class":274},"() ",[257,576,434],{"class":270},[257,578,579],{"class":303}," setShow",[257,581,440],{"class":274},[257,583,584],{"class":320},"true",[257,586,587],{"class":274},")",[257,589,364],{"class":270},[257,591,592],{"class":274},">Show comments\u003C\u002F",[257,594,566],{"class":345},[257,596,597],{"class":274},">;\n",[257,599,600],{"class":259,"line":376},[257,601,373],{"class":274},[257,603,604],{"class":259,"line":382},[257,605,606],{"class":263},"\u002F\u002F trade-off: loading on click adds a short delay when the user asks for comments;\n",[257,608,610],{"class":259,"line":609},9,[257,611,612],{"class":263},"\u002F\u002F load on visibility instead if most readers open them.\n",[230,614,616],{"id":615},"_4-trim-shared-dependencies","4. Trim shared dependencies",[15,618,619,620,623],{},"Replace heavy libraries with lighter ones, import specific modules instead of whole packages, use ",[33,621,622],{},"optimizePackageImports"," for supported libraries, and drop polyfills for browsers outside your support targets.",[15,625,626],{},[40,627,47,630,47,633,47,636,47,638,47,655,47,658,47,660,47,666,47,672,47,677,47,683,47,687,47,690,47,693,47,697,47,700,47,703,47,707,47,711,47,713,47,716,47,719,47,721,47,724,47,727,47,735,47,739,47,743,47,747,47],{"viewBox":628,"width":43,"role":44,"ariaLabel":629,"style":46},"0 0 760 232","Steps for reducing first-load JavaScript in a Next.js route.",[49,631],{"className":632,"x":53,"y":53,"width":43,"height":43,"fill":54},[52],[56,634,635],{},"First Load JS reduction workflow",[60,637,629],{},[639,640,641],"defs",{},[642,643,650],"marker",{"id":644,"viewBox":645,"refX":646,"refY":647,"markerWidth":648,"markerHeight":648,"orient":649},"fab818b11c","0 0 10 10","9","5","7","auto-start-reverse",[651,652],"path",{"d":653,"fill":69,"style":654},"M0 0 L10 5 L0 10 z","fill-opacity:0.7",[49,656],{"x":64,"y":64,"width":65,"height":657,"rx":67,"fill":68,"stroke":69,"style":70},"230",[72,659,635],{"x":74,"y":75,"fill":69,"style":76},[49,661],{"x":74,"y":87,"width":662,"height":663,"rx":664,"fill":91,"stroke":91,"style":665},"208.0","55.0","6","fill-opacity:0.14;stroke-opacity:0.9",[72,667,671],{"x":113,"y":668,"fill":69,"style":669,"textAnchor":670},"78.0","font-size:13px;font-weight:700","middle","Analyse",[72,673,676],{"x":113,"y":674,"fill":69,"style":675,"textAnchor":670},"96.0","font-size:12px","build output + analyzer",[49,678],{"x":679,"y":87,"width":662,"height":663,"rx":664,"fill":680,"stroke":681,"style":682},"276.0","#ffc300","#b8860b","fill-opacity:0.24;stroke-opacity:0.9",[72,684,686],{"x":685,"y":668,"fill":69,"style":669,"textAnchor":670},"380.0","Boundaries",[72,688,689],{"x":685,"y":674,"fill":69,"style":675,"textAnchor":670},"use client at leaves",[49,691],{"x":692,"y":87,"width":662,"height":663,"rx":664,"fill":91,"stroke":91,"style":665},"524.0",[72,694,696],{"x":695,"y":668,"fill":69,"style":669,"textAnchor":670},"628.0","Server work",[72,698,699],{"x":695,"y":674,"fill":69,"style":675,"textAnchor":670},"format\u002Frender on server",[49,701],{"x":692,"y":702,"width":662,"height":663,"rx":664,"fill":91,"stroke":91,"style":665},"155.0",[72,704,706],{"x":695,"y":705,"fill":69,"style":669,"textAnchor":670},"177.0","Defer",[72,708,710],{"x":695,"y":709,"fill":69,"style":675,"textAnchor":670},"195.0","next\u002Fdynamic widgets",[49,712],{"x":679,"y":702,"width":662,"height":663,"rx":664,"fill":91,"stroke":91,"style":665},[72,714,715],{"x":685,"y":705,"fill":69,"style":669,"textAnchor":670},"Trim deps",[72,717,718],{"x":685,"y":709,"fill":69,"style":675,"textAnchor":670},"lighter imports",[49,720],{"x":74,"y":702,"width":662,"height":663,"rx":664,"fill":91,"stroke":91,"style":665},[72,722,723],{"x":113,"y":705,"fill":69,"style":669,"textAnchor":670},"Budget",[72,725,726],{"x":113,"y":709,"fill":69,"style":675,"textAnchor":670},"CI check",[259,728],{"x1":729,"y1":730,"x2":731,"y2":730,"stroke":69,"strokeWidth":732,"style":733,"markerEnd":734},"236.0","83.5","274.0","1.5","stroke-opacity:0.6","url(#fab818b11c)",[259,736],{"x1":737,"y1":730,"x2":738,"y2":730,"stroke":69,"strokeWidth":732,"style":733,"markerEnd":734},"484.0","522.0",[259,740],{"x1":695,"y1":741,"x2":695,"y2":742,"stroke":69,"strokeWidth":732,"style":733,"markerEnd":734},"111.0","153.0",[259,744],{"x1":692,"y1":745,"x2":746,"y2":745,"stroke":69,"strokeWidth":732,"style":733,"markerEnd":734},"182.5","486.0",[259,748],{"x1":679,"y1":745,"x2":749,"y2":745,"stroke":69,"strokeWidth":732,"style":733,"markerEnd":734},"238.0",[148,751,753],{"id":752},"verification","Verification",[15,755,756,757,759],{},"Re-run ",[33,758,164],{}," and compare First Load JS per route. In the analyzer, confirm removed libraries no longer appear in client chunks. Record a lab trace on a throttled profile: hydration tasks should be shorter. In the field, compare INP and TBT-related metrics per route.",[148,761,763],{"id":762},"worked-example-a-documentation-site","Worked Example: A Documentation Site",[15,765,766,767,770,771,774,775,778],{},"A documentation site built with the App Router had 210KB First Load JS on every docs page. The analyzer showed a syntax highlighter (60KB), a markdown parser (30KB) and a search modal (45KB) in the shared chunk, because the docs layout was a client component that used ",[33,768,769],{},"usePathname"," for active link highlighting and imported the search modal statically. The team moved active-link logic into a small client ",[33,772,773],{},"NavLink"," component, made the layout a Server Component, rendered markdown and highlighting on the server, and loaded the search modal with ",[33,776,777],{},"next\u002Fdynamic"," on first keyboard shortcut or click. First Load JS dropped to 95KB, TBT on mobile by 380ms, and INP p75 from 220ms to 140ms.",[15,780,781],{},[40,782,47,785,47,788,47,791,47,793,47,796,47,798,47,805,47,810,47,814,47,817,47,821,47,826,47,830,47,834,47,838,47,842,47,846,47,850,47,854,47],{"viewBox":783,"width":43,"role":44,"ariaLabel":784,"style":46},"0 0 760 216","Bar chart of first-load JavaScript for documentation pages after successive reductions.",[49,786],{"className":787,"x":53,"y":53,"width":43,"height":43,"fill":54},[52],[56,789,790],{},"First Load JS for docs pages after each change",[60,792,784],{},[49,794],{"x":64,"y":64,"width":65,"height":795,"rx":67,"fill":68,"stroke":69,"style":70},"214",[72,797,790],{"x":74,"y":75,"fill":69,"style":76},[259,799],{"x1":800,"y1":801,"x2":800,"y2":137,"stroke":681,"strokeWidth":732,"strokeDashArray":802,"style":804},"503.7","72.0",[803,803],"4","stroke-opacity:0.9",[72,806,809],{"x":807,"y":808,"fill":69,"style":81,"textAnchor":82},"224.8","92.0","Client layout + static imports",[49,811],{"x":812,"y":668,"width":813,"height":89,"rx":90,"fill":68,"stroke":69,"style":106},"236.8","431.2",[72,815,816],{"x":95,"y":808,"fill":69,"style":96},"210KB",[72,818,820],{"x":807,"y":819,"fill":69,"style":81,"textAnchor":82},"123.0","Server layout, client NavLink",[49,822],{"x":812,"y":823,"width":824,"height":89,"rx":90,"fill":680,"stroke":681,"style":825},"109.0","338.8","fill-opacity:0.7;stroke-opacity:0.9",[72,827,829],{"x":828,"y":819,"fill":69,"style":96},"581.6","165KB",[72,831,833],{"x":807,"y":832,"fill":69,"style":81,"textAnchor":82},"154.0","Markdown + highlighting on server",[49,835],{"x":812,"y":836,"width":837,"height":89,"rx":90,"fill":91,"stroke":91,"style":92},"140.0","246.4",[72,839,841],{"x":840,"y":832,"fill":69,"style":96},"489.2","120KB",[72,843,845],{"x":807,"y":844,"fill":69,"style":81,"textAnchor":82},"185.0","Search modal via next\u002Fdynamic",[49,847],{"x":812,"y":848,"width":849,"height":89,"rx":90,"fill":680,"stroke":681,"style":825},"171.0","195.1",[72,851,853],{"x":852,"y":844,"fill":69,"style":96},"437.9","95KB",[72,855,859],{"x":800,"y":856,"fill":857,"style":858,"textAnchor":670},"68.0","#8a6608","font-size:12px;font-weight:700","budget",[148,861,863],{"id":862},"budgets-in-ci","Budgets in CI",[15,865,866,867,869,870,873],{},"Bundle size regresses one dependency at a time. Add a CI step that parses ",[33,868,164],{}," output (or ",[33,871,872],{},".next\u002F"," build manifests) and fails if First Load JS for key routes grows beyond a set budget or by more than a set percentage. Tools exist for this, or a small script can compare against a stored baseline. Pair it with the bundle analyzer report as a build artefact, so reviewers can see what changed when the check fails.",[248,875,877],{"className":250,"code":876,"language":252,"meta":253,"style":253},"\u002F\u002F scripts\u002Fcheck-first-load.mjs — fail if a route exceeds its budget (KB).\nconst budgets = { '\u002F': 110, '\u002Fblog\u002F[slug]': 120, '\u002Fproduct\u002F[id]': 140 };\nconst out = await (await import('node:fs\u002Fpromises')).readFile('build-output.txt', 'utf8');\nfor (const [route, kb] of Object.entries(budgets)) {\n  const m = out.match(new RegExp(`${route.replace(\u002F[[\\]]\u002Fg, '\\\\$&')}\\\\s+.*?([\\\\d.]+) kB\\\\s*$`, 'm'));\n  if (m && Number(m[1]) > kb) { console.error(`${route}: ${m[1]} kB > ${kb} kB`); process.exitCode = 1; }\n}\n\u002F\u002F trade-off: parsing human-readable build output is brittle across versions;\n\u002F\u002F prefer reading build manifests if your Next.js version exposes them.\n",[33,878,879,884,928,969,1002,1096,1165,1169,1174],{"__ignoreMap":253},[257,880,881],{"class":259,"line":260},[257,882,883],{"class":263},"\u002F\u002F scripts\u002Fcheck-first-load.mjs — fail if a route exceeds its budget (KB).\n",[257,885,886,888,891,893,896,899,902,905,907,910,912,915,917,920,922,925],{"class":259,"line":267},[257,887,420],{"class":270},[257,889,890],{"class":320}," budgets",[257,892,324],{"class":270},[257,894,895],{"class":274}," { ",[257,897,898],{"class":281},"'\u002F'",[257,900,901],{"class":274},": ",[257,903,904],{"class":320},"110",[257,906,507],{"class":274},[257,908,909],{"class":281},"'\u002Fblog\u002F[slug]'",[257,911,901],{"class":274},[257,913,914],{"class":320},"120",[257,916,507],{"class":274},[257,918,919],{"class":281},"'\u002Fproduct\u002F[id]'",[257,921,901],{"class":274},[257,923,924],{"class":320},"140",[257,926,927],{"class":274}," };\n",[257,929,930,932,935,937,939,941,944,946,948,951,954,957,959,962,964,967],{"class":259,"line":288},[257,931,420],{"class":270},[257,933,934],{"class":320}," out",[257,936,324],{"class":270},[257,938,327],{"class":270},[257,940,171],{"class":274},[257,942,943],{"class":270},"await",[257,945,437],{"class":270},[257,947,440],{"class":274},[257,949,950],{"class":281},"'node:fs\u002Fpromises'",[257,952,953],{"class":274},")).",[257,955,956],{"class":303},"readFile",[257,958,440],{"class":274},[257,960,961],{"class":281},"'build-output.txt'",[257,963,507],{"class":274},[257,965,966],{"class":281},"'utf8'",[257,968,530],{"class":274},[257,970,971,974,976,978,980,983,985,988,990,993,996,999],{"class":259,"line":314},[257,972,973],{"class":270},"for",[257,975,171],{"class":274},[257,977,420],{"class":270},[257,979,501],{"class":274},[257,981,982],{"class":320},"route",[257,984,507],{"class":274},[257,986,987],{"class":320},"kb",[257,989,513],{"class":274},[257,991,992],{"class":270},"of",[257,994,995],{"class":274}," Object.",[257,997,998],{"class":303},"entries",[257,1000,1001],{"class":274},"(budgets)) {\n",[257,1003,1004,1006,1009,1011,1014,1017,1019,1022,1025,1027,1030,1032,1035,1038,1040,1043,1046,1050,1053,1055,1058,1060,1063,1066,1069,1071,1073,1075,1078,1080,1083,1085,1088,1090,1093],{"class":259,"line":336},[257,1005,317],{"class":270},[257,1007,1008],{"class":320}," m",[257,1010,324],{"class":270},[257,1012,1013],{"class":274}," out.",[257,1015,1016],{"class":303},"match",[257,1018,440],{"class":274},[257,1020,1021],{"class":270},"new",[257,1023,1024],{"class":303}," RegExp",[257,1026,440],{"class":274},[257,1028,1029],{"class":281},"`${",[257,1031,982],{"class":274},[257,1033,1034],{"class":281},".",[257,1036,1037],{"class":303},"replace",[257,1039,440],{"class":281},[257,1041,1042],{"class":281},"\u002F",[257,1044,1045],{"class":320},"[[",[257,1047,1049],{"class":1048},"sn2CQ","\\]",[257,1051,1052],{"class":320},"]",[257,1054,1042],{"class":281},[257,1056,1057],{"class":270},"g",[257,1059,507],{"class":281},[257,1061,1062],{"class":281},"'",[257,1064,1065],{"class":270},"\\\\",[257,1067,1068],{"class":281},"$&'",[257,1070,587],{"class":281},[257,1072,364],{"class":281},[257,1074,1065],{"class":270},[257,1076,1077],{"class":281},"s+.*?([",[257,1079,1065],{"class":270},[257,1081,1082],{"class":281},"d.]+) kB",[257,1084,1065],{"class":270},[257,1086,1087],{"class":281},"s*$`",[257,1089,507],{"class":274},[257,1091,1092],{"class":281},"'m'",[257,1094,1095],{"class":274},"));\n",[257,1097,1098,1101,1104,1107,1110,1113,1115,1118,1121,1124,1127,1129,1131,1133,1136,1139,1142,1144,1146,1149,1151,1154,1157,1159,1162],{"class":259,"line":370},[257,1099,1100],{"class":270},"  if",[257,1102,1103],{"class":274}," (m ",[257,1105,1106],{"class":270},"&&",[257,1108,1109],{"class":303}," Number",[257,1111,1112],{"class":274},"(m[",[257,1114,64],{"class":320},[257,1116,1117],{"class":274},"]) ",[257,1119,1120],{"class":270},">",[257,1122,1123],{"class":274}," kb) { console.",[257,1125,1126],{"class":303},"error",[257,1128,440],{"class":274},[257,1130,1029],{"class":281},[257,1132,982],{"class":274},[257,1134,1135],{"class":281},"}: ${",[257,1137,1138],{"class":274},"m",[257,1140,1141],{"class":281},"[",[257,1143,64],{"class":320},[257,1145,1052],{"class":281},[257,1147,1148],{"class":281},"} kB > ${",[257,1150,987],{"class":274},[257,1152,1153],{"class":281},"} kB`",[257,1155,1156],{"class":274},"); process.exitCode ",[257,1158,516],{"class":270},[257,1160,1161],{"class":320}," 1",[257,1163,1164],{"class":274},"; }\n",[257,1166,1167],{"class":259,"line":376},[257,1168,373],{"class":274},[257,1170,1171],{"class":259,"line":382},[257,1172,1173],{"class":263},"\u002F\u002F trade-off: parsing human-readable build output is brittle across versions;\n",[257,1175,1176],{"class":259,"line":609},[257,1177,1178],{"class":263},"\u002F\u002F prefer reading build manifests if your Next.js version exposes them.\n",[148,1180,1182],{"id":1181},"hydration-beyond-bundle-size","Hydration Beyond Bundle Size",[15,1184,1185],{},"Smaller bundles reduce download and parse time, but hydration cost also depends on how many client components render on load. A page with 90KB of JavaScript that hydrates 500 client components can still produce long tasks. Keep client components small and few, use Suspense boundaries to split hydration, and avoid rendering hidden interactive UI (menus, modals) on load.",[148,1187,1189],{"id":1188},"common-mistakes","Common Mistakes",[153,1191,1192,1200,1206,1214],{},[156,1193,1194,1199],{},[159,1195,1196,1198],{},[33,1197,35],{}," in the root layout."," The most common cause of large bundles.",[156,1201,1202,1205],{},[159,1203,1204],{},"Formatting libraries in client components."," Format on the server instead.",[156,1207,1208,1211,1212,1034],{},[159,1209,1210],{},"Static imports of rarely used widgets."," Use ",[33,1213,777],{},[156,1215,1216,1219],{},[159,1217,1218],{},"Measuring uncompressed sizes."," First Load JS is compressed; compare like with like.",[148,1221,1223],{"id":1222},"edge-cases","Edge Cases",[15,1225,1226,1229],{},[159,1227,1228],{},"Context providers."," Providers must be client components; place them as low as possible and keep their dependencies small.",[15,1231,1232,1235],{},[159,1233,1234],{},"Third-party UI libraries."," Some require client components for everything; consider lighter or server-compatible alternatives for static parts.",[15,1237,1238,1241,1242,1042,1245,1034],{},[159,1239,1240],{},"Pages Router."," Without Server Components, focus on dynamic imports, dependency trimming and moving logic to ",[33,1243,1244],{},"getStaticProps",[33,1246,1247],{},"getServerSideProps",[15,1249,1250,1253],{},[159,1251,1252],{},"Shared chunks."," Code used by many routes lands in shared chunks loaded everywhere; keep shared code lean.",[148,1255,1257],{"id":1256},"faq","FAQ",[1259,1260,1263,1267],"details",{"className":1261},[1262],"faq-item",[1264,1265,1266],"summary",{},"What is First Load JS?",[15,1268,1269,1270,1034],{},"The compressed JavaScript required for the first visit to a route, including shared chunks, as reported by ",[33,1271,164],{},[1259,1273,1275,1278],{"className":1274},[1262],[1264,1276,1277],{},"Does \"use client\" make a component render only on the client?",[15,1279,1280],{},"No. Client components still render on the server for the initial HTML, but their code ships to the browser and they hydrate.",[1259,1282,1284,1287],{"className":1283},[1262],[1264,1285,1286],{},"How do I find which library is largest?",[15,1288,1289,1290,1292],{},"Use ",[33,1291,178],{}," and inspect the client chunks for the route.",[1259,1294,1296,1299],{"className":1295},[1262],[1264,1297,1298],{},"Should I use next\u002Fdynamic with ssr: false?",[15,1300,1301],{},"Only for components that need browser APIs during render. Otherwise keep SSR so the HTML includes the content, and defer only the JavaScript.",[1259,1303,1305,1308],{"className":1304},[1262],[1264,1306,1307],{},"Does reducing First Load JS improve LCP?",[15,1309,1310],{},"Sometimes, by reducing competition for bandwidth and main-thread time. The bigger effects are usually on INP and TBT.",[1259,1312,1314,1317],{"className":1313},[1262],[1264,1315,1316],{},"What is optimizePackageImports?",[15,1318,1319],{},"A Next.js option that rewrites imports from supported libraries so only the modules you use are bundled, avoiding barrel-file bloat.",[1259,1321,1323,1326],{"className":1322},[1262],[1264,1324,1325],{},"Can I check bundle size in pull requests?",[15,1327,1328,1329,1331],{},"Yes. Compare First Load JS from ",[33,1330,164],{}," against a baseline in CI and comment or fail when routes grow.",[1259,1333,1335,1338],{"className":1334},[1262],[1264,1336,1337],{},"Do Server Actions add client JavaScript?",[15,1339,1340],{},"A small amount for the client-side invocation. The action's implementation stays on the server.",[1259,1342,1344,1347],{"className":1343},[1262],[1264,1345,1346],{},"Does Turbopack change bundle size?",[15,1348,1349],{},"Bundler choice can affect output slightly, but First Load JS is driven mostly by what your code imports and where client boundaries sit. The same fixes apply.",[148,1351,1353],{"id":1352},"related","Related",[153,1355,1356,1362,1369],{},[156,1357,1358,1361],{},[19,1359,1360],{"href":21},"Next.js performance"," — the topic overview.",[156,1363,1364,1368],{},[19,1365,1367],{"href":1366},"\u002Fframework-performance\u002Fnextjs-performance\u002Fchoosing-next-script-loading-strategies\u002F","Choosing next\u002Fscript loading strategies"," — third-party code outside the bundle.",[156,1370,1371,1375],{},[19,1372,1374],{"href":1373},"\u002Fjavascript-bundle-optimization-code-splitting\u002F","JavaScript bundle optimization"," — general bundle techniques.",[1377,1378,1380],"script",{"type":1379},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"How to Reduce Next.js First Load JavaScript\",\n  \"description\": \"A practical workflow for finding and removing client JavaScript from Next.js routes, using bundle analysis, Server Components and dynamic imports.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Move client boundaries to the leaves\",\n      \"text\": \"Keep layouts, pages and content components as Server Components.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Move non-interactive work to the server\",\n      \"text\": \"Format dates, render markdown and highlight code in Server Components, so those libraries never reach the client.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Defer heavy client components\",\n      \"text\": \"Defer heavy client components\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Trim shared dependencies\",\n      \"text\": \"Replace heavy libraries with lighter ones, import specific modules instead of whole packages, use optimizePackageImports for supported libraries, and drop polyfills for browsers outside your support targets.\"\n    }\n  ]\n}\n",[1377,1382,1383],{"type":1379},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"How to Reduce Next.js First Load JavaScript\",\n  \"description\": \"A practical workflow for finding and removing client JavaScript from Next.js routes, using bundle analysis, Server Components and dynamic imports.\",\n  \"datePublished\": \"2026-10-06\",\n  \"dateModified\": \"2026-10-06\",\n  \"author\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"publisher\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"mainEntityOfPage\": {\n    \"@type\": \"WebPage\",\n    \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Fframework-performance\u002Fnextjs-performance\u002Freducing-nextjs-first-load-javascript\u002F\"\n  }\n}\n",[1377,1385,1386],{"type":1379},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 1,\n      \"name\": \"Home\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 2,\n      \"name\": \"Framework Performance\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fframework-performance\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 3,\n      \"name\": \"Next.js Performance\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fframework-performance\u002Fnextjs-performance\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"Reducing Next.js First Load JavaScript\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fframework-performance\u002Fnextjs-performance\u002Freducing-nextjs-first-load-javascript\u002F\"\n    }\n  ]\n}\n",[1388,1389,1390],"style",{},"html pre.shiki code .sjfSM, html code.shiki .sjfSM{--shiki-default:#66707B;--shiki-dark:#BDC4CC;--shiki-light:#66707B}html pre.shiki code .sPARh, html code.shiki .sPARh{--shiki-default:#A0111F;--shiki-dark:#FF9492;--shiki-light:#A0111F}html pre.shiki code .saISM, html code.shiki .saISM{--shiki-default:#0E1116;--shiki-dark:#F0F3F6;--shiki-light:#0E1116}html pre.shiki code .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}html pre.shiki code .sQw3B, html code.shiki .sQw3B{--shiki-default:#702C00;--shiki-dark:#FFB757;--shiki-light:#702C00}html pre.shiki code .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}html pre.shiki code .sZBmE, html code.shiki .sZBmE{--shiki-default:#024C1A;--shiki-dark:#72F088;--shiki-light:#024C1A}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html pre.shiki code .sn2CQ, html code.shiki .sn2CQ{--shiki-default:#024C1A;--shiki-default-font-weight:bold;--shiki-dark:#72F088;--shiki-dark-font-weight:bold;--shiki-light:#024C1A;--shiki-light-font-weight:bold}",{"title":253,"searchDepth":267,"depth":267,"links":1392},[1393,1394,1395,1401,1402,1403,1404,1405,1406,1407,1408],{"id":150,"depth":267,"text":151},{"id":196,"depth":267,"text":197},{"id":227,"depth":267,"text":228,"children":1396},[1397,1398,1399,1400],{"id":232,"depth":288,"text":233},{"id":242,"depth":288,"text":243},{"id":388,"depth":288,"text":389},{"id":615,"depth":288,"text":616},{"id":752,"depth":267,"text":753},{"id":762,"depth":267,"text":763},{"id":862,"depth":267,"text":863},{"id":1181,"depth":267,"text":1182},{"id":1188,"depth":267,"text":1189},{"id":1222,"depth":267,"text":1223},{"id":1256,"depth":267,"text":1257},{"id":1352,"depth":267,"text":1353},"A practical workflow for finding and removing client JavaScript from Next.js routes, using bundle analysis, Server Components and dynamic imports.","md",{"slug":1412,"type":346,"breadcrumb":1413,"datePublished":1420,"dateModified":1420},"reducing-nextjs-first-load-javascript",[1414,1416,1417,1418],{"name":1415,"url":1042},"Home",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":1419},"\u002Fframework-performance\u002Fnextjs-performance\u002Freducing-nextjs-first-load-javascript\u002F","2026-10-06",true,"\u002Fframework-performance\u002Fnextjs-performance\u002Freducing-nextjs-first-load-javascript",{"title":1424,"description":1425},"Reducing First Load JS in Next.js Apps","Shrink Next.js First Load JS: analyse chunks, move use client boundaries to leaves, defer heavy components with next\u002Fdynamic, and trim shared layout dependencies.","framework-performance\u002Fnextjs-performance\u002Freducing-nextjs-first-load-javascript\u002Findex","fPN36oR1XX6vPI9-gdYgw0yzLJQOnKdnXwH63G8Aqnw",[1429,1433],{"title":1430,"path":1431,"stem":1432,"children":-1},"Next.js Partial Prerendering","\u002Fframework-performance\u002Fnextjs-performance\u002Fnextjs-partial-prerendering","framework-performance\u002Fnextjs-performance\u002Fnextjs-partial-prerendering\u002Findex",{"title":1434,"path":1435,"stem":1436,"children":-1},"React Rendering Performance","\u002Fframework-performance\u002Freact-rendering-performance","framework-performance\u002Freact-rendering-performance\u002Findex",1791308072420]