[{"data":1,"prerenderedAt":1096},["ShallowReactive",2],{"content:\u002Fjavascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002Fislands-vs-full-hydration-for-content-sites":3,"surroundings:\u002Fjavascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002Fislands-vs-full-hydration-for-content-sites":1087},{"id":4,"title":5,"body":6,"description":1068,"extension":1069,"meta":1070,"navigation":1081,"path":1082,"seo":1083,"stem":1085,"__hash__":1086},"content\u002Fjavascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002Fislands-vs-full-hydration-for-content-sites\u002Findex.md","Islands vs Full Hydration for Content Sites",{"type":7,"value":8,"toc":1059},"minimark",[9,14,29,34,68,72,172,296,300,306,312,318,332,336,342,506,509,515,673,676,691,697,929,932,936,939,942,953,957,969,983,992,1001,1010,1019,1023,1044,1049,1052,1055],[10,11,13],"h1",{"id":12},"islands-vs-full-hydration-which-should-a-content-site-choose","Islands vs Full Hydration: Which Should a Content Site Choose?",[15,16,17,18,23,24,28],"p",{},"This comparison sits under ",[19,20,22],"a",{"href":21},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002F","Hydration & Partial Rehydration Strategies"," in ",[19,25,27],{"href":26},"\u002Fjavascript-bundle-optimization-code-splitting\u002F","JavaScript Bundle Optimization & Code Splitting",". Both architectures server-render the same HTML and both can produce a fast first paint. They differ in what happens next: full hydration re-creates the entire component tree on the client, islands re-create only the parts you marked. That single difference decides your interaction latency, your bundle size, and how hard cross-component state becomes.",[30,31,33],"h2",{"id":32},"rapid-diagnosis-measure-your-interactive-ratio","Rapid Diagnosis: Measure Your Interactive Ratio",[35,36,37,45,51,62],"ul",{},[38,39,40,44],"li",{},[41,42,43],"strong",{},"Count interactive components as a share of total."," Below ~20%, islands will win decisively. Above ~60%, the state-sharing cost usually outweighs the savings.",[38,46,47,50],{},[41,48,49],{},"Check whether interactivity is clustered or scattered."," Three self-contained widgets suit islands. Fifty controls that all read the same store do not.",[38,52,53,56,57,61],{},[41,54,55],{},"Look at your current hydration task."," If it is under ",[58,59,60],"code",{},"50ms"," on a throttled profile, you have no problem to solve and a migration would be pure cost.",[38,63,64,67],{},[41,65,66],{},"Ask how much shared client state exists."," A theme toggle and a cart badge are cheap to externalise. A multi-step form spanning six components is not.",[30,69,71],{"id":70},"the-comparison","The Comparison",[73,74,75,91],"table",{},[76,77,78],"thead",{},[79,80,81,85,88],"tr",{},[82,83,84],"th",{},"Axis",[82,86,87],{},"Islands",[82,89,90],{},"Full hydration",[92,93,94,106,117,128,139,150,161],"tbody",{},[79,95,96,100,103],{},[97,98,99],"td",{},"JavaScript shipped",[97,101,102],{},"Only marked components",[97,104,105],{},"Whole tree plus framework runtime",[79,107,108,111,114],{},[97,109,110],{},"Hydration cost",[97,112,113],{},"One short task per island",[97,115,116],{},"One long task for the tree",[79,118,119,122,125],{},[97,120,121],{},"Interaction latency after load",[97,123,124],{},"Low — thread is mostly idle",[97,126,127],{},"Elevated until the tree settles",[79,129,130,133,136],{},[97,131,132],{},"Shared client state",[97,134,135],{},"External store or events only",[97,137,138],{},"Native context and stores",[79,140,141,144,147],{},[97,142,143],{},"Client-side routing",[97,145,146],{},"Usually absent or opt-in",[97,148,149],{},"Built in",[79,151,152,155,158],{},[97,153,154],{},"Migration effort from an existing SSR app",[97,156,157],{},"High — component-by-component",[97,159,160],{},"None",[79,162,163,166,169],{},[97,164,165],{},"Best fit",[97,167,168],{},"Docs, marketing, blogs, catalogues",[97,170,171],{},"Dashboards, editors, apps",[173,174,181,182,189,190,189,194,189,198,189,207,189,214,189,223,189,230,189,235,189,242,189,246,189,249,189,253,189,257,189,260,189,266,189,270,189,274,189,277,189,280,189,283,189,286,189,291,189],"svg",{"xmlns":175,"viewBox":176,"width":177,"role":178,"ariaLabel":179,"style":180},"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","0 0 760 258","100%","img","Chart plotting the share of interactive components against which architecture wins, with islands winning below twenty percent, either viable in the middle, and full hydration winning above sixty percent","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)","\n  ",[183,184],"rect",{"className":185,"x":187,"y":187,"width":177,"height":177,"fill":188},[186],"svg-canvas","0","#ffffff"," ",[191,192,193],"title",{},"Choosing by interactive ratio",[195,196,197],"desc",{},"A horizontal scale from zero to one hundred percent interactive components, divided into an islands zone below twenty percent, a mixed zone from twenty to sixty, and a full hydration zone above sixty, with example site types under each.",[183,199],{"x":200,"y":200,"width":201,"height":202,"rx":203,"fill":204,"stroke":205,"style":206},"1","758","256","10","none","currentColor","stroke-opacity:0.18",[208,209,213],"text",{"x":210,"y":211,"fill":205,"style":212},"24","32","font-size:16px;font-weight:700","What share of your components respond to input?",[183,215],{"x":216,"y":217,"width":218,"height":219,"rx":220,"fill":221,"stroke":221,"style":222},"40","64","180","46","6","#0466c8","fill-opacity:0.2;stroke-opacity:0.55",[208,224,229],{"x":225,"y":226,"fill":205,"style":227,"textAnchor":228},"130","84","font-size:12px;font-weight:700;","middle","0–20%",[208,231,234],{"x":225,"y":232,"fill":205,"style":233,"textAnchor":228},"102","font-size:11px;","islands win clearly",[183,236],{"x":237,"y":217,"width":238,"height":219,"rx":220,"fill":239,"stroke":240,"style":241},"220","280","#ffc300","#b8860b","fill-opacity:0.24",[208,243,245],{"x":244,"y":226,"fill":205,"style":227,"textAnchor":228},"360","20–60%",[208,247,248],{"x":244,"y":232,"fill":205,"style":233,"textAnchor":228},"either works — decide on state coupling",[183,250],{"x":251,"y":217,"width":237,"height":219,"rx":220,"fill":205,"stroke":205,"style":252},"500","fill-opacity:0.08;stroke-opacity:0.35",[208,254,256],{"x":255,"y":226,"fill":205,"style":227,"textAnchor":228},"610","60–100%",[208,258,259],{"x":255,"y":232,"fill":205,"style":233,"textAnchor":228},"full hydration wins",[261,262],"line",{"x1":216,"y1":263,"x2":264,"y2":263,"stroke":205,"style":265},"126","720","stroke-opacity:0.35",[208,267,269],{"x":225,"y":268,"fill":205,"style":233,"textAnchor":228},"152","docs · blog · marketing",[208,271,273],{"x":225,"y":272,"fill":205,"style":233,"textAnchor":228},"170","product catalogue",[208,275,276],{"x":244,"y":268,"fill":205,"style":233,"textAnchor":228},"news site with a live feed",[208,278,279],{"x":244,"y":272,"fill":205,"style":233,"textAnchor":228},"commerce category page",[208,281,282],{"x":255,"y":268,"fill":205,"style":233,"textAnchor":228},"dashboard · editor",[208,284,285],{"x":255,"y":272,"fill":205,"style":233,"textAnchor":228},"multi-step checkout",[261,287],{"x1":210,"y1":288,"x2":289,"y2":288,"stroke":205,"style":290},"196","736","stroke-opacity:0.2",[208,292,295],{"x":210,"y":293,"fill":205,"style":294},"224","font-size:11.5px;fill-opacity:0.85","The ratio is measurable today: count components with event handlers or state against total rendered components.",[30,297,299],{"id":298},"root-cause-analysis-where-each-model-actually-costs-you","Root Cause Analysis: Where Each Model Actually Costs You",[15,301,302,305],{},[41,303,304],{},"1. Islands break the shared-state assumption."," Each island is a separate root. React context, framework stores and prop drilling stop at the island boundary, so a cart badge in the header and an add-to-cart button in the body cannot share a provider. You need an external store, custom events, or URL state — a real refactor in a mature codebase.",[15,307,308,311],{},[41,309,310],{},"2. Full hydration pays for components that never change."," A prose article of 300 static nodes is instantiated on the client for no benefit whatsoever. That is the cost islands delete, and it scales with page length, which is exactly why content sites feel it most.",[15,313,314,317],{},[41,315,316],{},"3. Islands complicate client-side routing."," Without a client router, every navigation is a document load. That is often fine — and with a modern view-transition or prefetch layer it can feel instant — but it changes how you think about preserving state across pages.",[15,319,320,323,324,327,328,331],{},[41,321,322],{},"4. Full hydration hides its cost behind a fast paint."," LCP looks healthy because the HTML arrived early, so teams routinely ship a page with a ",[58,325,326],{},"1.3s"," LCP and a ",[58,329,330],{},"500ms"," INP and believe they have a fast site. Only interaction measurements reveal the problem.",[30,333,335],{"id":334},"step-by-step-resolution-making-the-call","Step-by-Step Resolution: Making the Call",[15,337,338,341],{},[41,339,340],{},"1. Measure the interactive ratio."," Do this before any architectural debate.",[343,344,349],"pre",{"className":345,"code":346,"language":347,"meta":348,"style":348},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F\u002F Rough census: how many rendered elements actually have behaviour?\nconst all = document.querySelectorAll('body *').length;\nconst interactive = document.querySelectorAll(\n  'button, a[href], input, select, textarea, [role=\"button\"], [tabindex]'\n).length;\nconsole.log(`${interactive}\u002F${all} = ${(interactive \u002F all * 100).toFixed(1)}% interactive`);\n\u002F\u002F trade-off: this counts DOM elements, not components, so it over-counts links\n\u002F\u002F in prose. Treat it as an order-of-magnitude signal and confirm against your\n\u002F\u002F component tree before committing to a migration.\n","javascript","",[58,350,351,359,397,414,420,429,488,494,500],{"__ignoreMap":348},[352,353,355],"span",{"class":261,"line":354},1,[352,356,358],{"class":357},"sjfSM","\u002F\u002F Rough census: how many rendered elements actually have behaviour?\n",[352,360,362,366,370,373,377,381,384,388,391,394],{"class":261,"line":361},2,[352,363,365],{"class":364},"sPARh","const",[352,367,369],{"class":368},"sPXB4"," all",[352,371,372],{"class":364}," =",[352,374,376],{"class":375},"saISM"," document.",[352,378,380],{"class":379},"smZ65","querySelectorAll",[352,382,383],{"class":375},"(",[352,385,387],{"class":386},"sZ8jY","'body *'",[352,389,390],{"class":375},").",[352,392,393],{"class":368},"length",[352,395,396],{"class":375},";\n",[352,398,400,402,405,407,409,411],{"class":261,"line":399},3,[352,401,365],{"class":364},[352,403,404],{"class":368}," interactive",[352,406,372],{"class":364},[352,408,376],{"class":375},[352,410,380],{"class":379},[352,412,413],{"class":375},"(\n",[352,415,417],{"class":261,"line":416},4,[352,418,419],{"class":386},"  'button, a[href], input, select, textarea, [role=\"button\"], [tabindex]'\n",[352,421,423,425,427],{"class":261,"line":422},5,[352,424,390],{"class":375},[352,426,393],{"class":368},[352,428,396],{"class":375},[352,430,432,435,438,440,443,446,449,452,455,457,459,462,464,467,470,472,475,477,479,482,485],{"class":261,"line":431},6,[352,433,434],{"class":375},"console.",[352,436,437],{"class":379},"log",[352,439,383],{"class":375},[352,441,442],{"class":386},"`${",[352,444,445],{"class":375},"interactive",[352,447,448],{"class":386},"}\u002F${",[352,450,451],{"class":375},"all",[352,453,454],{"class":386},"} = ${",[352,456,383],{"class":386},[352,458,445],{"class":375},[352,460,461],{"class":364}," \u002F",[352,463,369],{"class":375},[352,465,466],{"class":364}," *",[352,468,469],{"class":368}," 100",[352,471,390],{"class":386},[352,473,474],{"class":379},"toFixed",[352,476,383],{"class":386},[352,478,200],{"class":368},[352,480,481],{"class":386},")",[352,483,484],{"class":386},"}% interactive`",[352,486,487],{"class":375},");\n",[352,489,491],{"class":261,"line":490},7,[352,492,493],{"class":357},"\u002F\u002F trade-off: this counts DOM elements, not components, so it over-counts links\n",[352,495,497],{"class":261,"line":496},8,[352,498,499],{"class":357},"\u002F\u002F in prose. Treat it as an order-of-magnitude signal and confirm against your\n",[352,501,503],{"class":261,"line":502},9,[352,504,505],{"class":357},"\u002F\u002F component tree before committing to a migration.\n",[15,507,508],{},"Expected outcome: a number that usually settles the argument — content sites typically land under 10%.",[15,510,511,514],{},[41,512,513],{},"2. If islands look right, start with the heaviest route, not the whole site."," A single high-traffic template proves the model and surfaces the state-sharing problems early.",[343,516,520],{"className":517,"code":518,"language":519,"meta":348,"style":348},"language-jsx shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F\u002F One route, three islands: everything else is HTML.\n\u003CArticleLayout>\n  \u003CTableOfContents client:idle \u002F>      {\u002F* nice to have, not urgent *\u002F}\n  \u003Carticle>{content}\u003C\u002Farticle>          {\u002F* zero JS *\u002F}\n  \u003CNewsletterForm client:visible \u002F>     {\u002F* below the fold *\u002F}\n  \u003CThemeToggle client:load \u002F>           {\u002F* must work immediately *\u002F}\n\u003C\u002FArticleLayout>\n\u002F\u002F trade-off: three islands means three small bundles and three hydration tasks\n\u002F\u002F instead of one. Below roughly a dozen islands per page that is a clear win;\n\u002F\u002F past that, the per-island overhead starts to add up.\n","jsx",[58,521,522,527,539,568,601,625,649,657,662,667],{"__ignoreMap":348},[352,523,524],{"class":261,"line":354},[352,525,526],{"class":357},"\u002F\u002F One route, three islands: everything else is HTML.\n",[352,528,529,532,536],{"class":261,"line":361},[352,530,531],{"class":375},"\u003C",[352,533,535],{"class":534},"sZBmE","ArticleLayout",[352,537,538],{"class":375},">\n",[352,540,541,544,547,550,553,556,559,562,565],{"class":261,"line":399},[352,542,543],{"class":375},"  \u003C",[352,545,546],{"class":534},"TableOfContents",[352,548,549],{"class":368}," client",[352,551,552],{"class":375},":",[352,554,555],{"class":368},"idle",[352,557,558],{"class":375}," \u002F>      ",[352,560,561],{"class":364},"{",[352,563,564],{"class":357},"\u002F* nice to have, not urgent *\u002F",[352,566,567],{"class":364},"}\n",[352,569,570,572,575,578,580,583,586,589,591,594,596,599],{"class":261,"line":416},[352,571,543],{"class":375},[352,573,574],{"class":534},"article",[352,576,577],{"class":375},">",[352,579,561],{"class":364},[352,581,582],{"class":375},"content",[352,584,585],{"class":364},"}",[352,587,588],{"class":375},"\u003C\u002F",[352,590,574],{"class":534},[352,592,593],{"class":375},">          ",[352,595,561],{"class":364},[352,597,598],{"class":357},"\u002F* zero JS *\u002F",[352,600,567],{"class":364},[352,602,603,605,608,610,612,615,618,620,623],{"class":261,"line":422},[352,604,543],{"class":375},[352,606,607],{"class":534},"NewsletterForm",[352,609,549],{"class":368},[352,611,552],{"class":375},[352,613,614],{"class":368},"visible",[352,616,617],{"class":375}," \u002F>     ",[352,619,561],{"class":364},[352,621,622],{"class":357},"\u002F* below the fold *\u002F",[352,624,567],{"class":364},[352,626,627,629,632,634,636,639,642,644,647],{"class":261,"line":431},[352,628,543],{"class":375},[352,630,631],{"class":534},"ThemeToggle",[352,633,549],{"class":368},[352,635,552],{"class":375},[352,637,638],{"class":368},"load",[352,640,641],{"class":375}," \u002F>           ",[352,643,561],{"class":364},[352,645,646],{"class":357},"\u002F* must work immediately *\u002F",[352,648,567],{"class":364},[352,650,651,653,655],{"class":261,"line":490},[352,652,588],{"class":375},[352,654,535],{"class":534},[352,656,538],{"class":375},[352,658,659],{"class":261,"line":496},[352,660,661],{"class":357},"\u002F\u002F trade-off: three islands means three small bundles and three hydration tasks\n",[352,663,664],{"class":261,"line":502},[352,665,666],{"class":357},"\u002F\u002F instead of one. Below roughly a dozen islands per page that is a clear win;\n",[352,668,670],{"class":261,"line":669},10,[352,671,672],{"class":357},"\u002F\u002F past that, the per-island overhead starts to add up.\n",[15,674,675],{},"Expected outcome: hydration cost on that route drops by an order of magnitude while the rest of the site is untouched.",[15,677,678,681,682,686,687,690],{},[41,679,680],{},"3. If full hydration must stay, get the same benefit with deferral."," You do not need an architectural migration to stop hydrating off-screen components — see ",[19,683,685],{"href":684},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002Fdeferring-below-the-fold-hydration-with-intersectionobserver\u002F","deferring below-the-fold hydration"," for the pattern, and ",[19,688,689],{"href":21},"selective hydration with Suspense"," for splitting what remains.",[15,692,693,696],{},[41,694,695],{},"4. Externalise the state islands cannot share, once."," A tiny signal store or a typed event bus is usually 30 lines and removes the main blocker.",[343,698,700],{"className":345,"code":699,"language":347,"meta":348,"style":348},"\u002F\u002F A minimal cross-island store: no framework, no provider tree.\nconst listeners = new Set();\nlet cart = JSON.parse(localStorage.getItem('cart') || '[]');\nexport const getCart = () => cart;\nexport function setCart(next) {\n  cart = next;\n  localStorage.setItem('cart', JSON.stringify(cart));\n  listeners.forEach((fn) => fn(cart));\n}\nexport const subscribe = (fn) => (listeners.add(fn), () => listeners.delete(fn));\n\u002F\u002F trade-off: you are re-implementing a slice of what your framework gave you,\n\u002F\u002F including the SSR-safety rules. Keep the surface tiny — one store for the\n\u002F\u002F two or three values that genuinely cross islands, not a global state layer.\n",[58,701,702,707,725,767,789,808,818,844,867,871,911,917,923],{"__ignoreMap":348},[352,703,704],{"class":261,"line":354},[352,705,706],{"class":357},"\u002F\u002F A minimal cross-island store: no framework, no provider tree.\n",[352,708,709,711,714,716,719,722],{"class":261,"line":361},[352,710,365],{"class":364},[352,712,713],{"class":368}," listeners",[352,715,372],{"class":364},[352,717,718],{"class":364}," new",[352,720,721],{"class":379}," Set",[352,723,724],{"class":375},"();\n",[352,726,727,730,733,736,739,742,745,748,751,753,756,759,762,765],{"class":261,"line":399},[352,728,729],{"class":364},"let",[352,731,732],{"class":375}," cart ",[352,734,735],{"class":364},"=",[352,737,738],{"class":368}," JSON",[352,740,741],{"class":375},".",[352,743,744],{"class":379},"parse",[352,746,747],{"class":375},"(localStorage.",[352,749,750],{"class":379},"getItem",[352,752,383],{"class":375},[352,754,755],{"class":386},"'cart'",[352,757,758],{"class":375},") ",[352,760,761],{"class":364},"||",[352,763,764],{"class":386}," '[]'",[352,766,487],{"class":375},[352,768,769,772,775,778,780,783,786],{"class":261,"line":416},[352,770,771],{"class":364},"export",[352,773,774],{"class":364}," const",[352,776,777],{"class":379}," getCart",[352,779,372],{"class":364},[352,781,782],{"class":375}," () ",[352,784,785],{"class":364},"=>",[352,787,788],{"class":375}," cart;\n",[352,790,791,793,796,799,801,805],{"class":261,"line":422},[352,792,771],{"class":364},[352,794,795],{"class":364}," function",[352,797,798],{"class":379}," setCart",[352,800,383],{"class":375},[352,802,804],{"class":803},"sQw3B","next",[352,806,807],{"class":375},") {\n",[352,809,810,813,815],{"class":261,"line":431},[352,811,812],{"class":375},"  cart ",[352,814,735],{"class":364},[352,816,817],{"class":375}," next;\n",[352,819,820,823,826,828,830,833,836,838,841],{"class":261,"line":490},[352,821,822],{"class":375},"  localStorage.",[352,824,825],{"class":379},"setItem",[352,827,383],{"class":375},[352,829,755],{"class":386},[352,831,832],{"class":375},", ",[352,834,835],{"class":368},"JSON",[352,837,741],{"class":375},[352,839,840],{"class":379},"stringify",[352,842,843],{"class":375},"(cart));\n",[352,845,846,849,852,855,858,860,862,865],{"class":261,"line":496},[352,847,848],{"class":375},"  listeners.",[352,850,851],{"class":379},"forEach",[352,853,854],{"class":375},"((",[352,856,857],{"class":803},"fn",[352,859,758],{"class":375},[352,861,785],{"class":364},[352,863,864],{"class":379}," fn",[352,866,843],{"class":375},[352,868,869],{"class":261,"line":502},[352,870,567],{"class":375},[352,872,873,875,877,880,882,885,887,889,891,894,897,900,902,905,908],{"class":261,"line":669},[352,874,771],{"class":364},[352,876,774],{"class":364},[352,878,879],{"class":379}," subscribe",[352,881,372],{"class":364},[352,883,884],{"class":375}," (",[352,886,857],{"class":803},[352,888,758],{"class":375},[352,890,785],{"class":364},[352,892,893],{"class":375}," (listeners.",[352,895,896],{"class":379},"add",[352,898,899],{"class":375},"(fn), () ",[352,901,785],{"class":364},[352,903,904],{"class":375}," listeners.",[352,906,907],{"class":379},"delete",[352,909,910],{"class":375},"(fn));\n",[352,912,914],{"class":261,"line":913},11,[352,915,916],{"class":357},"\u002F\u002F trade-off: you are re-implementing a slice of what your framework gave you,\n",[352,918,920],{"class":261,"line":919},12,[352,921,922],{"class":357},"\u002F\u002F including the SSR-safety rules. Keep the surface tiny — one store for the\n",[352,924,926],{"class":261,"line":925},13,[352,927,928],{"class":357},"\u002F\u002F two or three values that genuinely cross islands, not a global state layer.\n",[15,930,931],{},"Expected outcome: islands can coordinate without a shared component tree, at the cost of a small hand-written module.",[30,933,935],{"id":934},"verification","Verification",[15,937,938],{},"Compare the two architectures on the same route with the same content, on a throttled profile. The numbers that should move are total blocking time and the duration of the longest task after first paint; LCP should be roughly unchanged, because both models paint the same server HTML.",[15,940,941],{},"Then check the thing migrations most often break: interactivity that used to work. Walk the route with the keyboard, confirm every control still responds, and confirm state that used to be shared still is. A silently dead island is easy to ship because the markup still looks right.",[15,943,944,945,948,949,952],{},"In the field, look at INP for interactions in the first two seconds after navigation. That is where full hydration's cost concentrates and where an islands migration shows its biggest gain — often the difference between a ",[58,946,947],{},"340ms"," and a ",[58,950,951],{},"90ms"," p75 on mid-tier mobile.",[30,954,956],{"id":955},"faq","FAQ",[958,959,962,966],"details",{"className":960},[961],"faq-item",[963,964,965],"summary",{},"Can I use islands inside an existing React app?",[15,967,968],{},"Partially. You can mount independent roots for interactive widgets and leave the rest as server-rendered HTML, which is islands in everything but name. What you cannot easily keep is a single React context spanning them — each root is isolated. For most apps the pragmatic path is deferral and selective hydration first, and a genuine islands framework only when starting a new surface.",[958,970,972,975],{"className":971},[961],[963,973,974],{},"Do islands hurt SEO or accessibility?",[15,976,977,978,982],{},"No. Both models emit the same server-rendered HTML, and islands emit ",[979,980,981],"em",{},"less"," JavaScript on top of it, so crawlers see identical content. The accessibility risk is the same in both: an interactive control that never hydrates is inert. Test with the keyboard after any change to hydration timing, because that is where a silent failure hides.",[958,984,986,989],{"className":985},[961],[963,987,988],{},"What about client-side routing — do I lose instant navigation?",[15,990,991],{},"You lose the framework's built-in router, but not necessarily the feel. Prefetching the next document on hover or viewport entry, plus view transitions, gets most content sites to navigation that is indistinguishable from a client router — without shipping one. Where you genuinely need preserved client state across navigations, that is a signal your site is closer to an app than a content site.",[958,993,995,998],{"className":994},[961],[963,996,997],{},"How long does an islands migration usually take?",[15,999,1000],{},"Plan it per template rather than per site, because the effort is dominated by untangling shared state rather than by moving markup. A content template with two or three self-contained widgets is often a day; a template whose components all read from one context can take a week, most of it spent deciding what the external store should look like. Migrating the highest-traffic template first gives you the measurement and the state design before you commit to the rest.",[958,1002,1004,1007],{"className":1003},[961],[963,1005,1006],{},"Can the two architectures coexist in one codebase?",[15,1008,1009],{},"Yes, and that is usually how a migration actually happens. Content routes become islands while application routes keep full hydration, sharing components through a package that works under both. The friction to watch for is a shared component that quietly depends on a context: it works in the app and silently fails in an island. Make that dependency explicit — a prop or an external store — and the same component can serve both.",[958,1011,1013,1016],{"className":1012},[961],[963,1014,1015],{},"Does an islands framework help if my pages are already fast?",[15,1017,1018],{},"Then it is not worth the migration. The gains here are real but bounded: they come from deleting hydration work that a fast page does not have. If your longest task after paint is already under the long-task line and your field INP is comfortably inside budget, the architecture is not your constraint, and the effort belongs somewhere the measurements point to.",[30,1020,1022],{"id":1021},"related","Related",[35,1024,1025,1030,1037],{},[38,1026,1027,1029],{},[19,1028,22],{"href":21}," — the cost model behind both architectures.",[38,1031,1032,1036],{},[19,1033,1035],{"href":1034},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002Ffixing-long-hydration-tasks-in-nextjs-app-router\u002F","Fixing long hydration tasks in Next.js App Router"," — getting island-like behaviour inside a full-hydration framework.",[38,1038,1039,1043],{},[19,1040,1042],{"href":1041},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fdynamic-imports-and-route-based-splitting\u002F","Dynamic Imports & Route-Based Splitting"," — the chunking strategy that pairs with either model.",[1045,1046,1048],"script",{"type":1047},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"Choose between islands and full hydration\",\n  \"description\": \"Measure the share of genuinely interactive components, pilot islands on the heaviest route, or achieve the same effect with deferral inside a full-hydration framework.\",\n  \"step\": [\n    { \"@type\": \"HowToStep\", \"position\": 1, \"name\": \"Measure the interactive ratio\", \"text\": \"Count interactive elements against total rendered elements to see which architecture your page shape favours.\", \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002Fislands-vs-full-hydration-for-content-sites\u002F#step-by-step-resolution-making-the-call\" },\n    { \"@type\": \"HowToStep\", \"position\": 2, \"name\": \"Pilot one route\", \"text\": \"Convert the heaviest template to islands first so state-sharing problems surface early.\", \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002Fislands-vs-full-hydration-for-content-sites\u002F#step-by-step-resolution-making-the-call\" },\n    { \"@type\": \"HowToStep\", \"position\": 3, \"name\": \"Or defer instead of migrating\", \"text\": \"Use lazy and selective hydration to stop hydrating off-screen components without an architectural change.\", \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002Fislands-vs-full-hydration-for-content-sites\u002F#step-by-step-resolution-making-the-call\" },\n    { \"@type\": \"HowToStep\", \"position\": 4, \"name\": \"Externalise shared state\", \"text\": \"Replace cross-component context with a minimal external store so isolated islands can coordinate.\", \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002Fislands-vs-full-hydration-for-content-sites\u002F#step-by-step-resolution-making-the-call\" }\n  ]\n}\n",[1045,1050,1051],{"type":1047},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"Islands vs Full Hydration: Which Should a Content Site Choose?\",\n  \"description\": \"A decision matrix comparing islands architecture and whole-tree hydration on JavaScript shipped, interaction latency, shared state and migration effort.\",\n  \"datePublished\": \"2026-08-01\",\n  \"dateModified\": \"2026-08-01\",\n  \"author\": { \"@type\": \"Organization\", \"name\": \"frontend-performance.com\" },\n  \"publisher\": { \"@type\": \"Organization\", \"name\": \"frontend-performance.com\" },\n  \"mainEntityOfPage\": { \"@type\": \"WebPage\", \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002Fislands-vs-full-hydration-for-content-sites\u002F\" }\n}\n",[1045,1053,1054],{"type":1047},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    { \"@type\": \"ListItem\", \"position\": 1, \"name\": \"Home\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\" },\n    { \"@type\": \"ListItem\", \"position\": 2, \"name\": \"JavaScript Bundle Optimization & Code Splitting\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002F\" },\n    { \"@type\": \"ListItem\", \"position\": 3, \"name\": \"Hydration & Partial Rehydration Strategies\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002F\" },\n    { \"@type\": \"ListItem\", \"position\": 4, \"name\": \"Islands vs Full Hydration for Content Sites\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002Fislands-vs-full-hydration-for-content-sites\u002F\" }\n  ]\n}\n",[1056,1057,1058],"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 .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}html pre.shiki code .saISM, html code.shiki .saISM{--shiki-default:#0E1116;--shiki-dark:#F0F3F6;--shiki-light:#0E1116}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}html pre.shiki code .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}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 .sZBmE, html code.shiki .sZBmE{--shiki-default:#024C1A;--shiki-dark:#72F088;--shiki-light:#024C1A}html pre.shiki code .sQw3B, html code.shiki .sQw3B{--shiki-default:#702C00;--shiki-dark:#FFB757;--shiki-light:#702C00}",{"title":348,"searchDepth":361,"depth":361,"links":1060},[1061,1062,1063,1064,1065,1066,1067],{"id":32,"depth":361,"text":33},{"id":70,"depth":361,"text":71},{"id":298,"depth":361,"text":299},{"id":334,"depth":361,"text":335},{"id":934,"depth":361,"text":935},{"id":955,"depth":361,"text":956},{"id":1021,"depth":361,"text":1022},"Islands delete hydration work; full hydration keeps shared state simple. Which trade-off wins depends on how much of your page is genuinely interactive.","md",{"slug":1071,"type":574,"breadcrumb":1072,"datePublished":1080,"dateModified":1080},"islands-vs-full-hydration-for-content-sites",[1073,1076,1077,1078],{"name":1074,"url":1075},"Home","\u002F",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":1079},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002Fislands-vs-full-hydration-for-content-sites\u002F","2026-08-01",true,"\u002Fjavascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002Fislands-vs-full-hydration-for-content-sites",{"title":5,"description":1084},"A decision matrix for islands architecture versus whole-tree hydration: JavaScript shipped, interaction latency, shared state cost, and migration effort per site type.","javascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002Fislands-vs-full-hydration-for-content-sites\u002Findex","NsHkxFvi_xaGCeGfYzats5Iu6_EYLAldS0f0TsiAESk",[1088,1092],{"title":1089,"path":1090,"stem":1091,"children":-1},"Fixing Long Hydration Tasks in Next.js App Router","\u002Fjavascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002Ffixing-long-hydration-tasks-in-nextjs-app-router","javascript-bundle-optimization-code-splitting\u002Fhydration-and-partial-rehydration-strategies\u002Ffixing-long-hydration-tasks-in-nextjs-app-router\u002Findex",{"title":1093,"path":1094,"stem":1095,"children":-1},"Modern Module Formats: ESM vs CommonJS","\u002Fjavascript-bundle-optimization-code-splitting\u002Fmodern-module-formats-esm-vs-commonjs","javascript-bundle-optimization-code-splitting\u002Fmodern-module-formats-esm-vs-commonjs\u002Findex",1785622406844]