[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"categories-en":3,"post:\u002Fpost\u002Fnextjs-16-ppr-eliminate-the-static-vs-dynamic-tradeoff-and-achieve-edge-ttfb-with-fresh-data":37},[4,11,17,24,30],{"id":5,"slug":6,"name":7,"colorHex":8,"iconName":9,"postCount":10},"0e2c1225-f78a-4c20-8c93-998ab9dc93b9","frontend","Frontend","#40484f",null,25,{"id":12,"slug":13,"name":14,"colorHex":15,"iconName":9,"postCount":16},"bc8df70e-b7fb-4d89-a80c-fd458d36d58c","code-development","Code & Development","#8b5cf6",23,{"id":18,"slug":19,"name":20,"colorHex":21,"iconName":22,"postCount":23},"550e8400-e29b-41d4-a716-446655440001","inteligencia-artificial","Artificial Intelligence","#6366f1","brain",14,{"id":25,"slug":26,"name":27,"colorHex":28,"iconName":9,"postCount":29},"ea63b69c-2eb4-4100-81f3-70ce52d33743","tech-news","Tech News","#e50606",4,{"id":31,"slug":32,"name":33,"colorHex":34,"iconName":35,"postCount":36},"550e8400-e29b-41d4-a716-446655440017","how-to-guides","How-To & Guides","#be123c","book-open",2,{"post":38,"related":1733,"translations":1807,"resolved":9},{"id":39,"slug":40,"title":41,"excerpt":42,"image":43,"featured":44,"groupId":45,"publishedAt":46,"readingTime":23,"views":47,"author":48,"category":50,"tags":51,"contentJson":61,"metaTitle":1730,"metaDescription":1731,"updatedAt":1732},"e63ce578-4726-46d2-8045-df6e4243657a","nextjs-16-ppr-eliminate-the-static-vs-dynamic-tradeoff-and-achieve-edge-ttfb-with-fresh-data","Next.js 16 PPR: Eliminate the static vs. dynamic tradeoff and achieve Edge TTFB with fresh data","Partial Prerendering in Next.js 16 resolves the classic rendering tradeoff, delivering static speed with dynamic data in one seamless response.","https:\u002F\u002Fmfgiomkkbihnlpfdxwrt.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fblog-assets\u002Fmedia\u002Ffeatured\u002F1783970715281-featured-ikveub.webp",false,"4982f454-7d33-4921-a2b5-c1c663505594","2026-07-13T19:26:00.750741+00:00",1,{"name":49,"avatar":9},"Genildo Souza",{"slug":13,"name":14,"color":15},[52,55,58],{"slug":53,"name":54},"nextjs","Next.js",{"slug":56,"name":57},"react","React",{"slug":59,"name":60},"typescript","TypeScript",{"type":62,"content":63},"doc",[64,75,92,99,105,115,140,146,154,160,180,189,195,203,211,218,225,233,246,253,261,273,280,328,336,342,374,417,430,436,468,810,838,851,857,1189,1220,1355,1372,1419,1427,1433,1451,1457,1469,1547,1555,1707,1709],{"type":65,"attrs":66},"summaryBox",{"id":67,"items":68,"title":74},"sum_ftnl8x4x",[69,70,71,72,73],"Partial Prerendering eliminates the tradeoff between static and dynamic content by serving a static shell from the CDN while streaming dynamic parts.","Next.js 16 uses Suspense boundaries as the architectural dividing line to determine which parts of a page are prerendered and which are dynamic.","The framework now defaults to dynamic rendering, requiring developers to explicitly opt into static caching via the cacheComponents configuration.","Components accessing request-time APIs like cookies or headers automatically become dynamic holes that stream into the static shell at request time.","Developers can enable the new architecture by setting cacheComponents to true in the next.config.ts file for Next.js 16 applications.","Next.js Partial Prerendering Explained",{"type":76,"attrs":77,"content":79},"heading",{"id":78,"level":36},"h_opdqgvc4",[80,86],{"text":81,"type":82,"marks":83},"The oldest tradeoff in web development — ","text",[84],{"type":85},"bold",{"text":87,"type":82,"marks":88},"finally resolved",[89,90],{"type":85},{"type":91},"italic",{"type":93,"attrs":94,"content":96},"paragraph",{"id":95},"p_v8qpdzdj",[97],{"text":98,"type":82},"The agonizing choice between lightning-fast static pages and real-time dynamic content has long defined the Next.js development experience. But what if you never had to compromise again? With PPR, the static versus dynamic trade-off is finally obsolete.",{"type":93,"attrs":100,"content":102},{"id":101},"p_2ovow7sc",[103],{"text":104,"type":82},"Take a product page on an e-commerce site. The title, description, and images almost never change — they should be static, cached at the CDN edge, served in milliseconds. The user's cart count, their personalized recommendations, and real-time inventory — those change per request and per user. They have to be dynamic.",{"type":93,"attrs":106,"content":108},{"id":107},"p_sy8lxa0a",[109,111],{"text":110,"type":82},"Before PPR, you had to pick one mode for the entire route. Make it static and the cart is always stale. Make it SSR and every user pays the full server rendering cost — even for content that hasn't changed since the last deploy. ",{"text":112,"type":82,"marks":113},"PPR lets you have both, in one route, in one HTTP response.",[114],{"type":85},{"type":116,"attrs":117},"caseCards",{"id":118,"cards":119,"title":9},"case_mjda72nq",[120,125,130,135],{"tag":121,"body":122,"title":123,"status":124},"SSG \u002F ISR","HTML at build time. CDN cached. Fastest TTFB possible.\n\n✗ Stale user data. No personalization.","Static Generation","ok",{"tag":126,"body":127,"title":128,"status":129},"SSR","Fresh data on every request. Full personalization.\n\n✗ Slow TTFB. No CDN. Every user pays the cost.","Server Rendering","warn",{"tag":131,"body":132,"title":133,"status":134},"Streaming SSR","Sends chunks as they're ready. Progressive loading.\n\n✗ Entire page is dynamic. No static CDN shell.","Streaming","risk",{"tag":136,"body":137,"title":138,"status":139},"PPR · Next.js 16","Static shell from CDN. Dynamic parts streamed in the same response.\n\n✓ Edge TTFB + fresh data. Best of all strategies.","Partial Prerendering","info",{"type":141,"attrs":142},"pullquote",{"id":143,"quote":144,"accent":145,"attribution":9},"pq_rtc5645d","PPR is not a new rendering strategy. It's the end of the rendering strategy decision tree.","default",{"type":76,"attrs":147,"content":149},{"id":148,"level":36},"h_ganbhevs",[150],{"text":151,"type":82,"marks":152},"How PPR works under the hood",[153],{"type":85},{"type":93,"attrs":155,"content":157},{"id":156},"p_riuvfyx9",[158],{"text":159,"type":82},"The mental model is simpler than it sounds. One rule, one boundary, one response.",{"type":116,"attrs":161},{"id":162,"cards":163,"title":9},"case_ut0joo3d",[164,168,172,176],{"tag":165,"body":166,"title":167,"status":124},"Build time","At build time, Next.js renders everything it can — navigation, layout, headings, product descriptions, images, footers. Anything that doesn't depend on the incoming request. This becomes the static shell: a complete HTML document with Suspense fallback placeholders where the dynamic parts will go. The shell is stored at the CDN edge.","The static shell",{"tag":169,"body":170,"title":171,"status":129},"Request time","When a user requests the page, the CDN sends the cached shell immediately — that's your TTFB. In parallel, the origin server renders only the dynamic parts: the user's cart, their recommendations, real-time stock. These stream into the same HTTP response, filling the Suspense holes as they resolve. No second request. No client-side fetch. One response, two types of content.","The dynamic holes",{"tag":173,"body":174,"title":175,"status":134},"The boundary","Everything outside a \u003CSuspense> boundary is static — prerendered at build time, cached at the edge. Everything inside is dynamic — rendered at request time and streamed. The Suspense boundary is not just a loading UI: in PPR, it's the architectural boundary that separates static from dynamic.\n\n","\u003CSuspense> is the dividing line",{"tag":177,"body":178,"title":179,"status":139},"Next.js 16 change","In Next.js 16, all code is dynamic by default. You opt into static caching using the \"use cache\" directive or Suspense structure. This is the inverse of previous versions where pages were static by default. The experimental.ppr flag is gone — replaced by cacheComponents: true.\n\n","Dynamic by default",{"type":76,"attrs":181,"content":184},{"id":182,"level":183},"h_4bdyjcjw",3,[185],{"text":186,"type":82,"marks":187},"Enabling PPR in Next.js 16",[188],{"type":85},{"type":93,"attrs":190,"content":192},{"id":191},"p_mx63ot9v",[193],{"text":194,"type":82},"One config flag. That's the entire setup to unlock Partial Prerendering for your application.",{"type":196,"attrs":197,"content":200},"codeBlock",{"id":198,"language":59,"highlighted":199},"p_zvyxpgin","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">next.config.ts — enable Cache \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">Components\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (Next.js \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">16\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F next.config.ts — Next.js 16+\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> type\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { NextConfig } \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> 'next'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> nextConfig\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> NextConfig\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F Enables Partial Prerendering + Cache Components\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  cacheComponents: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">true\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">};\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">export\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> default\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> nextConfig;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F ⚠️ If you're on Next.js 14 or 15, use the old experimental flag:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F const nextConfig = { experimental: { ppr: 'incremental' } }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F The experimental.ppr flag was REMOVED in Next.js 16\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[201],{"text":202,"type":82},"next.config.ts — enable Cache Components (Next.js 16)\n\n\u002F\u002F next.config.ts — Next.js 16+\nimport type { NextConfig } from 'next';\n\nconst nextConfig: NextConfig = {\n  \u002F\u002F Enables Partial Prerendering + Cache Components\n  cacheComponents: true,\n};\n\nexport default nextConfig;\n\n\u002F\u002F ⚠️ If you're on Next.js 14 or 15, use the old experimental flag:\n\u002F\u002F const nextConfig = { experimental: { ppr: 'incremental' } }\n\u002F\u002F The experimental.ppr flag was REMOVED in Next.js 16",{"type":76,"attrs":204,"content":206},{"id":205,"level":183},"h_jka1fi3j",[207],{"text":208,"type":82,"marks":209},"Your first PPR page — product listing example",[210],{"type":85},{"type":196,"attrs":212,"content":215},{"id":213,"language":59,"highlighted":214},"p_au59b9pr","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">app\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">products\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">[id]\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">page.tsx — static shell \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">+\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> dynamic holes\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { Suspense }            \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> 'react'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { ProductDetails }      \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '.\u002Fproduct-details'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;   \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F static\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { UserCart }            \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '.\u002Fuser-cart'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;          \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F dynamic\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { Recommendations }     \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '.\u002Frecommendations'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;    \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F dynamic\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { CartSkeleton }        \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '.\u002Fskeletons'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { RecommendationsSkeleton } \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> '.\u002Fskeletons'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F This page uses PPR — shell is prerendered, holes are streamed\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">export\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> default\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> async\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> function\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> ProductPage\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  params\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">  params\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">id\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> string\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> };\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">main\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      {\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F*\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">        ✅ STATIC SHELL\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">        ProductDetails only uses params.id — known at build time\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">        Next.js prerenders this and caches it at the CDN edge\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">      *\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">      &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">ProductDetails productId\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">{params.id} \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      {\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F*\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">        ✅ DYNAMIC HOLE #1 — reads cookies() inside\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">        Wrapped in Suspense → streams at request time\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">        CartSkeleton shows immediately while UserCart loads\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">      *\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">      &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">Suspense fallback\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">{&#x3C;CartSkeleton \u002F>}\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">        &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">UserCart \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">      &#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">Suspense\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      {\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F*\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">        ✅ DYNAMIC HOLE #2 — personalized per user\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">        Streams in parallel with UserCart — no waterfall\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">      *\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">      &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">Suspense fallback\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">{&#x3C;RecommendationsSkeleton \u002F>}\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">        &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">Recommendations productId\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">{params.id} \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">      &#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">Suspense\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    &#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">main\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  );\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[216],{"text":217,"type":82},"app\u002Fproducts\u002F[id]\u002Fpage.tsx — static shell + dynamic holes\n\nimport { Suspense }            from 'react';\nimport { ProductDetails }      from '.\u002Fproduct-details';   \u002F\u002F static\nimport { UserCart }            from '.\u002Fuser-cart';          \u002F\u002F dynamic\nimport { Recommendations }     from '.\u002Frecommendations';    \u002F\u002F dynamic\nimport { CartSkeleton }        from '.\u002Fskeletons';\nimport { RecommendationsSkeleton } from '.\u002Fskeletons';\n\n\u002F\u002F This page uses PPR — shell is prerendered, holes are streamed\nexport default async function ProductPage({\n  params,\n}: {\n  params: { id: string };\n}) {\n  return (\n    \u003Cmain>\n      {\u002F*\n        ✅ STATIC SHELL\n        ProductDetails only uses params.id — known at build time\n        Next.js prerenders this and caches it at the CDN edge\n      *\u002F}\n      \u003CProductDetails productId={params.id} \u002F>\n\n      {\u002F*\n        ✅ DYNAMIC HOLE #1 — reads cookies() inside\n        Wrapped in Suspense → streams at request time\n        CartSkeleton shows immediately while UserCart loads\n      *\u002F}\n      \u003CSuspense fallback={\u003CCartSkeleton \u002F>}>\n        \u003CUserCart \u002F>\n      \u003C\u002FSuspense>\n\n      {\u002F*\n        ✅ DYNAMIC HOLE #2 — personalized per user\n        Streams in parallel with UserCart — no waterfall\n      *\u002F}\n      \u003CSuspense fallback={\u003CRecommendationsSkeleton \u002F>}>\n        \u003CRecommendations productId={params.id} \u002F>\n      \u003C\u002FSuspense>\n    \u003C\u002Fmain>\n  );\n}",{"type":196,"attrs":219,"content":222},{"id":220,"language":59,"highlighted":221},"p_6vciwpx0","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">user\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">-\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">cart.tsx — dynamic \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">component\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (uses request\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">-\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">time \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">API\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F app\u002Fproducts\u002F[id]\u002Fuser-cart.tsx\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { cookies } \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> 'next\u002Fheaders'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">; \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F ← makes this component dynamic\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">export\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> async\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> function\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> UserCart\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">() {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> sessionToken\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">await\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> cookies\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">()).\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">get\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'session'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)?.value;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  if\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">!\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">sessionToken) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">div\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>Sign \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">in\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> to see your cart\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">&#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">div\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> cart\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> await\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> fetchCart\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(sessionToken); \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F fetch user-specific data\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">div className\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"cart\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">span\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>{cart.itemCount} items\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">&#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">span\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">span\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>${cart.total}\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">&#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">span\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    &#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">div\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  );\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F Why is this dynamic?\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F cookies() accesses the incoming HTTP request — unknown at build time.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F Any component that calls cookies(), headers(), or connection()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F is automatically dynamic in Next.js 16.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F PPR streams it in after the static shell is served.\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[223],{"text":224,"type":82},"user-cart.tsx — dynamic component (uses request-time API)\n\u002F\u002F app\u002Fproducts\u002F[id]\u002Fuser-cart.tsx\nimport { cookies } from 'next\u002Fheaders'; \u002F\u002F ← makes this component dynamic\n\nexport async function UserCart() {\n  const sessionToken = (await cookies()).get('session')?.value;\n\n  if (!sessionToken) {\n    return \u003Cdiv>Sign in to see your cart\u003C\u002Fdiv>;\n  }\n\n  const cart = await fetchCart(sessionToken); \u002F\u002F fetch user-specific data\n\n  return (\n    \u003Cdiv className=\"cart\">\n      \u003Cspan>{cart.itemCount} items\u003C\u002Fspan>\n      \u003Cspan>${cart.total}\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n  );\n}\n\n\u002F\u002F Why is this dynamic?\n\u002F\u002F cookies() accesses the incoming HTTP request — unknown at build time.\n\u002F\u002F Any component that calls cookies(), headers(), or connection()\n\u002F\u002F is automatically dynamic in Next.js 16.\n\u002F\u002F PPR streams it in after the static shell is served.",{"type":76,"attrs":226,"content":228},{"id":227,"level":183},"h_tc49l2op",[229],{"text":230,"type":82,"marks":231},"The \"use cache\" directive — fine-grained caching",[232],{"type":85},{"type":93,"attrs":234,"content":236},{"id":235},"p_w43p1rwp",[237,239,244],{"text":238,"type":82},"Beyond Suspense boundaries, Next.js 16 introduced the ",{"text":240,"type":82,"marks":241},"\"use cache\"",[242],{"type":243},"code",{"text":245,"type":82}," directive — a way to mark individual functions or components as cacheable at the server level.",{"type":196,"attrs":247,"content":250},{"id":248,"language":59,"highlighted":249},"p_t5mogw9n","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"use cache\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> — component\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">-\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">level caching\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F Cache an individual async function — not the whole component\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">async\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> function\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> getProductData\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">productId\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> string\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">  'use cache'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">; \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F ← this function's result is cached\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> data\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> await\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> db.products.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">findUnique\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({ where: { id: productId } });\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> data;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F Cache a component directly\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">async\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> function\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> ProductHeader\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({ \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">productId\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> }\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">productId\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> string\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> }) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">  'use cache'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">; \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F ← this component is cached at build time\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> product\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> await\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> getProductData\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(productId);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">header\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">h1\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>{product.title}\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">&#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">h1\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">p\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>{product.description}\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">&#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">p\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    &#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">header\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  );\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F The key insight in Next.js 16:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F \"use cache\" = explicit opt-in to static caching\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F No directive = dynamic by default\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F Suspense boundary = where dynamic content streams in\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F Together, \"use cache\" + Suspense = Partial Prerendering\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[251],{"text":252,"type":82},"\"use cache\" — component-level caching\n\u002F\u002F Cache an individual async function — not the whole component\nasync function getProductData(productId: string) {\n  'use cache'; \u002F\u002F ← this function's result is cached\n  const data = await db.products.findUnique({ where: { id: productId } });\n  return data;\n}\n\n\u002F\u002F Cache a component directly\nasync function ProductHeader({ productId }: { productId: string }) {\n  'use cache'; \u002F\u002F ← this component is cached at build time\n  const product = await getProductData(productId);\n  return (\n    \u003Cheader>\n      \u003Ch1>{product.title}\u003C\u002Fh1>\n      \u003Cp>{product.description}\u003C\u002Fp>\n    \u003C\u002Fheader>\n  );\n}\n\n\u002F\u002F The key insight in Next.js 16:\n\u002F\u002F \"use cache\" = explicit opt-in to static caching\n\u002F\u002F No directive = dynamic by default\n\u002F\u002F Suspense boundary = where dynamic content streams in\n\u002F\u002F\n\u002F\u002F Together, \"use cache\" + Suspense = Partial Prerendering",{"type":76,"attrs":254,"content":256},{"id":255,"level":183},"h_udy26toz",[257],{"text":258,"type":82,"marks":259},"Reading the build output",[260],{"type":85},{"type":93,"attrs":262,"content":264},{"id":263},"p_c39xvhxk",[265,267,271],{"text":266,"type":82},"The ",{"text":268,"type":82,"marks":269},"◐",[270],{"type":243},{"text":272,"type":82}," symbol in the build output is how you confirm PPR is working for a route.",{"type":196,"attrs":274,"content":277},{"id":275,"language":59,"highlighted":276},"p_emi3jx2v","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">Route\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (app)                Size    First Load \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">JS\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">◐ \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#DBEDFF\">products\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">[id]            \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">4.2\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> kB    \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">89\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> kB\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">○ \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">about                    \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">1.1\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> kB    \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">82\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> kB\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">● \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#DBEDFF\">blog\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">[slug]              \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">2.3\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> kB    \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">84\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> kB\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">λ \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">dashboard                \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">3.1\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> kB    \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">86\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> kB\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">○ Static    ● \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">SSG\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    ◐ Partial Prerendering    λ \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">Dynamic\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">SSR\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[278],{"text":279,"type":82},"Route (app)                Size    First Load JS\n◐ \u002Fproducts\u002F[id]            4.2 kB    89 kB\n○ \u002Fabout                    1.1 kB    82 kB\n● \u002Fblog\u002F[slug]              2.3 kB    84 kB\nλ \u002Fdashboard                3.1 kB    86 kB\n○ Static    ● SSG    ◐ Partial Prerendering    λ Dynamic (SSR)",{"type":281,"attrs":282,"content":285},"callout",{"id":283,"type":284,"title":9},"call_g68fbu3u","warning",[286,294],{"type":93,"attrs":287,"content":289},{"id":288},"p_q3bpxezh",[290],{"text":291,"type":82,"marks":292},"⚠ Common issue",[293],{"type":85},{"type":93,"attrs":295,"content":297},{"id":296},"p_t3sc7w0h",[298,302,304,308,310,314,316,320,322,326],{"text":299,"type":82,"marks":300},"Page shows as λ (fully dynamic) instead of ◐ (PPR):",[301],{"type":85},{"text":303,"type":82}," a dynamic API — ",{"text":305,"type":82,"marks":306},"cookies()",[307],{"type":243},{"text":309,"type":82},", ",{"text":311,"type":82,"marks":312},"headers()",[313],{"type":243},{"text":315,"type":82},", or ",{"text":317,"type":82,"marks":318},"connection()",[319],{"type":243},{"text":321,"type":82}," — is being called outside a Suspense boundary, usually at the page or layout level. Find the call and move it inside a Suspense-wrapped component. The moment those APIs are inside a ",{"text":323,"type":82,"marks":324},"\u003CSuspense>",[325],{"type":243},{"text":327,"type":82},", Next.js can prerender everything outside it and the route becomes ◐.",{"type":76,"attrs":329,"content":331},{"id":330,"level":36},"h_237x7gto",[332],{"text":333,"type":82,"marks":334},"Migrating an SSR page to PPR",[335],{"type":85},{"type":93,"attrs":337,"content":339},{"id":338},"p_29o4baen",[340],{"text":341,"type":82},"Most SSR routes can become PPR routes with minimal changes. The key is identifying which parts need request-time data and wrapping them in Suspense.",{"type":343,"attrs":344,"content":346},"compare",{"id":345},"cmp_qrnkso1a",[347,361],{"type":348,"attrs":349,"content":353},"compareColumn",{"id":350,"side":351,"title":352},"col_yqqsgxlx","left","❌ Before — full SSR, slow TTFB",[354],{"type":196,"attrs":355,"content":358},{"id":356,"language":59,"highlighted":357},"p_8r4k6xl3","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F The whole page waits for user data\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F Even the static header is blocked\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">export\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> default\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> async\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> function\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> Page\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">() {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F ❌ All of this blocks the entire page\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> user\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> await\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> getUser\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();      \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F auth check\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> cart\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> await\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> getCart\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(user);  \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F user-specific\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> recs\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> await\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> getRecs\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(user);  \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F personalized\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> product\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> await\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> getProduct\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();   \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F static data\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F Nothing ships until ALL of these resolve\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">main\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">      &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">Header \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">      &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">ProductDetails product\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">{product} \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">      &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">CartWidget    cart\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">{cart} \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">      &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">Recommendations recs\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">{recs} \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    &#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">main\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  );\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[359],{"text":360,"type":82},"\u002F\u002F The whole page waits for user data\n\u002F\u002F Even the static header is blocked\nexport default async function Page() {\n  \u002F\u002F ❌ All of this blocks the entire page\n  const user    = await getUser();      \u002F\u002F auth check\n  const cart    = await getCart(user);  \u002F\u002F user-specific\n  const recs    = await getRecs(user);  \u002F\u002F personalized\n  const product = await getProduct();   \u002F\u002F static data\n\n  \u002F\u002F Nothing ships until ALL of these resolve\n  return (\n    \u003Cmain>\n      \u003CHeader \u002F>\n      \u003CProductDetails product={product} \u002F>\n      \u003CCartWidget    cart={cart} \u002F>\n      \u003CRecommendations recs={recs} \u002F>\n    \u003C\u002Fmain>\n  );\n}",{"type":348,"attrs":362,"content":366},{"id":363,"side":364,"title":365},"col_zsmhxlkz","right","✅ After — PPR, edge TTFB + fresh data",[367],{"type":196,"attrs":368,"content":371},{"id":369,"language":59,"highlighted":370},"p_g1im9i8l","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F Static content ships immediately from CDN\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F Dynamic content streams in parallel\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">export\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> default\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> async\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> function\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> Page\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({ \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">params\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> }) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F ✅ Only static data fetched at the page level\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> product\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> await\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> getProduct\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(params.id);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">main\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      {\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F* ✅ Static — in the prerendered shell \u002F}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">      &#x3C;Header \u002F>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">      &#x3C;ProductDetails product={product} \u002F>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">      {\u002F ✅ Dynamic — streamed at request time \u002F}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">      &#x3C;Suspense fallback={&#x3C;CartSkeleton \u002F>}>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">        &#x3C;CartWidget \u002F>        {\u002F fetches user + cart inside \u002F}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">      &#x3C;\u002FSuspense>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">      &#x3C;Suspense fallback={&#x3C;RecsSkeleton \u002F>}>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">        &#x3C;Recommendations id={params.id} \u002F> {\u002F personalized *\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">      &#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">Suspense\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    &#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">main\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  );\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[372],{"text":373,"type":82},"\u002F\u002F Static content ships immediately from CDN\n\u002F\u002F Dynamic content streams in parallel\nexport default async function Page({ params }) {\n  \u002F\u002F ✅ Only static data fetched at the page level\n  const product = await getProduct(params.id);\n\n  return (\n    \u003Cmain>\n      {\u002F* ✅ Static — in the prerendered shell \u002F}\n      \u003CHeader \u002F>\n      \u003CProductDetails product={product} \u002F>\n\n      {\u002F ✅ Dynamic — streamed at request time \u002F}\n      \u003CSuspense fallback={\u003CCartSkeleton \u002F>}>\n        \u003CCartWidget \u002F>        {\u002F fetches user + cart inside \u002F}\n      \u003C\u002FSuspense>\n\n      \u003CSuspense fallback={\u003CRecsSkeleton \u002F>}>\n        \u003CRecommendations id={params.id} \u002F> {\u002F personalized *\u002F}\n      \u003C\u002FSuspense>\n    \u003C\u002Fmain>\n  );\n}",{"type":281,"attrs":375,"content":378},{"id":376,"type":377,"title":9},"call_2h68uehe","tip",[379,387],{"type":93,"attrs":380,"content":382},{"id":381},"p_ztwnpp3n",[383],{"text":384,"type":82,"marks":385},"✓ Migration rule",[386],{"type":85},{"type":93,"attrs":388,"content":390},{"id":389},"p_96vogua3",[391,395,397,401,403,406,407,410,412,415],{"text":392,"type":82,"marks":393},"Move request-time data fetching down the tree.",[394],{"type":85},{"text":396,"type":82}," Any ",{"text":398,"type":82,"marks":399},"await",[400],{"type":243},{"text":402,"type":82}," that uses ",{"text":305,"type":82,"marks":404},[405],{"type":243},{"text":309,"type":82},{"text":311,"type":82,"marks":408},[409],{"type":243},{"text":411,"type":82},", or user-specific data should live inside a component that is wrapped in ",{"text":323,"type":82,"marks":413},[414],{"type":243},{"text":416,"type":82},". The page-level component should only fetch data that's known at build time — route params are fine; session tokens are not.",{"type":76,"attrs":418,"content":420},{"id":419,"level":36},"h_4q1dnceq",[421,425],{"text":422,"type":82,"marks":423},"Where PPR ",[424],{"type":85},{"text":426,"type":82,"marks":427},"breaks in production",[428,429],{"type":85},{"type":91},{"type":93,"attrs":431,"content":433},{"id":432},"p_pz9bycns",[434],{"text":435,"type":82},"PPR is not a magic bullet. There is one category of content where PPR can actually hurt you — and it's easy to miss in development.",{"type":281,"attrs":437,"content":439},{"id":438,"type":284,"title":9},"call_mhwidsmc",[440,448],{"type":93,"attrs":441,"content":443},{"id":442},"p_82uo3x6k",[444],{"text":445,"type":82,"marks":446},"⚠ The stale shell problem",[447],{"type":85},{"type":93,"attrs":449,"content":451},{"id":450},"p_xaxs2xkw",[452,456,458,462,464],{"text":453,"type":82,"marks":454},"PPR does not guarantee consistency between the static shell and the streamed content.",[455],{"type":85},{"text":457,"type":82}," If your pricing API updates every 30 seconds but the static shell is cached for 5 minutes, users see a stale price in the initial render, then a corrected price after the stream completes. In one documented e-commerce case, this caused a ",{"text":459,"type":82,"marks":460},"12% drop in conversion rate",[461],{"type":85},{"text":463,"type":82}," — users saw an outdated discount in the static shell and abandoned the cart before the dynamic price loaded. ",{"text":465,"type":82,"marks":466},"Never put price, inventory count, or time-sensitive offers in the static shell.",[467],{"type":85},{"type":469,"attrs":470,"content":472},"table",{"id":471},"tbl_v5y2rcm6",[473,510,544,575,606,641,674,709,742,775],{"type":474,"content":475},"tableRow",[476,488,499],{"type":477,"attrs":478,"content":479},"tableHeader",{"align":351,"colspan":47,"rowspan":47,"colwidth":9},[480],{"type":93,"attrs":481,"content":483},{"id":482},"p_fuujexvu",[484],{"text":485,"type":82,"marks":486},"Content type",[487],{"type":85},{"type":477,"attrs":489,"content":490},{"align":351,"colspan":47,"rowspan":47,"colwidth":9},[491],{"type":93,"attrs":492,"content":494},{"id":493},"p_gb7zzn44",[495],{"text":496,"type":82,"marks":497},"Put in static shell",[498],{"type":85},{"type":477,"attrs":500,"content":501},{"align":351,"colspan":47,"rowspan":47,"colwidth":9},[502],{"type":93,"attrs":503,"content":505},{"id":504},"p_thzneyea",[506],{"text":507,"type":82,"marks":508},"Keep in Suspense (dynamic)",[509],{"type":85},{"type":474,"content":511},[512,524,535],{"type":513,"attrs":514,"content":515},"tableCell",{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[516],{"type":93,"attrs":517,"content":519},{"id":518},"p_hkjfu549",[520],{"text":521,"type":82,"marks":522},"Product title, description, images",[523],{"type":85},{"type":513,"attrs":525,"content":526},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[527],{"type":93,"attrs":528,"content":530},{"id":529},"p_k6xeqlvl",[531],{"text":532,"type":82,"marks":533},"✓ Static shell",[534],{"type":85},{"type":513,"attrs":536,"content":537},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[538],{"type":93,"attrs":539,"content":541},{"id":540},"p_9zbcfpex",[542],{"text":543,"type":82},"—",{"type":474,"content":545},[546,557,567],{"type":513,"attrs":547,"content":548},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[549],{"type":93,"attrs":550,"content":552},{"id":551},"p_plxs469n",[553],{"text":554,"type":82,"marks":555},"Navigation, layout, footer",[556],{"type":85},{"type":513,"attrs":558,"content":559},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[560],{"type":93,"attrs":561,"content":563},{"id":562},"p_z7s03ytu",[564],{"text":532,"type":82,"marks":565},[566],{"type":85},{"type":513,"attrs":568,"content":569},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[570],{"type":93,"attrs":571,"content":573},{"id":572},"p_d5onq5zu",[574],{"text":543,"type":82},{"type":474,"content":576},[577,588,598],{"type":513,"attrs":578,"content":579},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[580],{"type":93,"attrs":581,"content":583},{"id":582},"p_24yvd89v",[584],{"text":585,"type":82,"marks":586},"Blog content, documentation",[587],{"type":85},{"type":513,"attrs":589,"content":590},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[591],{"type":93,"attrs":592,"content":594},{"id":593},"p_bz3cdr33",[595],{"text":532,"type":82,"marks":596},[597],{"type":85},{"type":513,"attrs":599,"content":600},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[601],{"type":93,"attrs":602,"content":604},{"id":603},"p_umlkyo06",[605],{"text":543,"type":82},{"type":474,"content":607},[608,619,630],{"type":513,"attrs":609,"content":610},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[611],{"type":93,"attrs":612,"content":614},{"id":613},"p_ykyimh1x",[615],{"text":616,"type":82,"marks":617},"User cart, wishlist",[618],{"type":85},{"type":513,"attrs":620,"content":621},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[622],{"type":93,"attrs":623,"content":625},{"id":624},"p_bmw1xutk",[626],{"text":627,"type":82,"marks":628},"✗ Never static",[629],{"type":85},{"type":513,"attrs":631,"content":632},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[633],{"type":93,"attrs":634,"content":636},{"id":635},"p_9fi2lj6h",[637],{"text":638,"type":82,"marks":639},"✓ Stream via Suspense",[640],{"type":85},{"type":474,"content":642},[643,654,664],{"type":513,"attrs":644,"content":645},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[646],{"type":93,"attrs":647,"content":649},{"id":648},"p_kf4imheb",[650],{"text":651,"type":82,"marks":652},"Personalized recommendations",[653],{"type":85},{"type":513,"attrs":655,"content":656},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[657],{"type":93,"attrs":658,"content":660},{"id":659},"p_jf39d2p0",[661],{"text":627,"type":82,"marks":662},[663],{"type":85},{"type":513,"attrs":665,"content":666},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[667],{"type":93,"attrs":668,"content":670},{"id":669},"p_854fhpxg",[671],{"text":638,"type":82,"marks":672},[673],{"type":85},{"type":474,"content":675},[676,687,698],{"type":513,"attrs":677,"content":678},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[679],{"type":93,"attrs":680,"content":682},{"id":681},"p_xcumcb6a",[683],{"text":684,"type":82,"marks":685},"Product price",[686],{"type":85},{"type":513,"attrs":688,"content":689},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[690],{"type":93,"attrs":691,"content":693},{"id":692},"p_b4pn9bkd",[694],{"text":695,"type":82,"marks":696},"✗ Avoid — stale risk",[697],{"type":85},{"type":513,"attrs":699,"content":700},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[701],{"type":93,"attrs":702,"content":704},{"id":703},"p_4iofjub8",[705],{"text":706,"type":82,"marks":707},"✓ Stream if it changes",[708],{"type":85},{"type":474,"content":710},[711,722,732],{"type":513,"attrs":712,"content":713},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[714],{"type":93,"attrs":715,"content":717},{"id":716},"p_dh1csb5a",[718],{"text":719,"type":82,"marks":720},"Real-time inventory count",[721],{"type":85},{"type":513,"attrs":723,"content":724},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[725],{"type":93,"attrs":726,"content":728},{"id":727},"p_za4chgk8",[729],{"text":627,"type":82,"marks":730},[731],{"type":85},{"type":513,"attrs":733,"content":734},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[735],{"type":93,"attrs":736,"content":738},{"id":737},"p_q318owdq",[739],{"text":638,"type":82,"marks":740},[741],{"type":85},{"type":474,"content":743},[744,755,765],{"type":513,"attrs":745,"content":746},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[747],{"type":93,"attrs":748,"content":750},{"id":749},"p_tkhrhs5h",[751],{"text":752,"type":82,"marks":753},"Authentication state",[754],{"type":85},{"type":513,"attrs":756,"content":757},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[758],{"type":93,"attrs":759,"content":761},{"id":760},"p_y332457j",[762],{"text":627,"type":82,"marks":763},[764],{"type":85},{"type":513,"attrs":766,"content":767},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[768],{"type":93,"attrs":769,"content":771},{"id":770},"p_xflttfyq",[772],{"text":638,"type":82,"marks":773},[774],{"type":85},{"type":474,"content":776},[777,788,799],{"type":513,"attrs":778,"content":779},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[780],{"type":93,"attrs":781,"content":783},{"id":782},"p_8u87kqok",[784],{"text":785,"type":82,"marks":786},"A\u002FB test variant",[787],{"type":85},{"type":513,"attrs":789,"content":790},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[791],{"type":93,"attrs":792,"content":794},{"id":793},"p_rabzsokt",[795],{"text":796,"type":82,"marks":797},"⚠ Only if tolerates stale",[798],{"type":85},{"type":513,"attrs":800,"content":801},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[802],{"type":93,"attrs":803,"content":805},{"id":804},"p_x65j59hw",[806],{"text":807,"type":82,"marks":808},"✓ Prefer Suspense",[809],{"type":85},{"type":281,"attrs":811,"content":813},{"id":812,"type":377,"title":9},"call_7l9vl0eg",[814,822],{"type":93,"attrs":815,"content":817},{"id":816},"p_im82b9cc",[818],{"text":819,"type":82,"marks":820},"→ The production rule",[821],{"type":85},{"type":93,"attrs":823,"content":825},{"id":824},"p_0fwdjfkg",[826,828,832,834],{"text":827,"type":82},"If a user might ",{"text":829,"type":82,"marks":830},"act on the static content before the dynamic content loads",[831],{"type":85},{"text":833,"type":82}," — clicking buy, adding to cart, making a decision based on price — PPR is the wrong choice for that content. Put it in Suspense. The rule: ",{"text":835,"type":82,"marks":836},"if it changes and it drives action, it must be dynamic.",[837],{"type":85},{"type":76,"attrs":839,"content":841},{"id":840,"level":36},"h_g4d76zeo",[842,846],{"text":843,"type":82,"marks":844},"PPR, SSR, SSG, ISR — ",[845],{"type":85},{"text":847,"type":82,"marks":848},"the strategy matrix",[849,850],{"type":85},{"type":91},{"type":93,"attrs":852,"content":854},{"id":853},"p_8sn6xj0h",[855],{"text":856,"type":82},"These aren't competing strategies. They're layers. PPR works best when 60%+ of your page is static.",{"type":469,"attrs":858,"content":860},{"id":859},"tbl_qkbltisq",[861,918,973,1026,1082,1135],{"type":474,"content":862},[863,874,885,896,907],{"type":477,"attrs":864,"content":865},{"align":351,"colspan":47,"rowspan":47,"colwidth":9},[866],{"type":93,"attrs":867,"content":869},{"id":868},"p_y3z661or",[870],{"text":871,"type":82,"marks":872},"Strategy",[873],{"type":85},{"type":477,"attrs":875,"content":876},{"align":351,"colspan":47,"rowspan":47,"colwidth":9},[877],{"type":93,"attrs":878,"content":880},{"id":879},"p_70xmcj4g",[881],{"text":882,"type":82,"marks":883},"TTFB",[884],{"type":85},{"type":477,"attrs":886,"content":887},{"align":351,"colspan":47,"rowspan":47,"colwidth":9},[888],{"type":93,"attrs":889,"content":891},{"id":890},"p_aloj20rw",[892],{"text":893,"type":82,"marks":894},"Fresh data",[895],{"type":85},{"type":477,"attrs":897,"content":898},{"align":351,"colspan":47,"rowspan":47,"colwidth":9},[899],{"type":93,"attrs":900,"content":902},{"id":901},"p_y70fld0z",[903],{"text":904,"type":82,"marks":905},"Personalized",[906],{"type":85},{"type":477,"attrs":908,"content":909},{"align":351,"colspan":47,"rowspan":47,"colwidth":9},[910],{"type":93,"attrs":911,"content":913},{"id":912},"p_hleu2tcw",[914],{"text":915,"type":82,"marks":916},"Use when",[917],{"type":85},{"type":474,"content":919},[920,931,942,953,964],{"type":513,"attrs":921,"content":922},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[923],{"type":93,"attrs":924,"content":926},{"id":925},"p_oo5wha09",[927],{"text":928,"type":82,"marks":929},"SSG",[930],{"type":85},{"type":513,"attrs":932,"content":933},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[934],{"type":93,"attrs":935,"content":937},{"id":936},"p_i49un7y7",[938],{"text":939,"type":82,"marks":940},"Edge speed",[941],{"type":85},{"type":513,"attrs":943,"content":944},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[945],{"type":93,"attrs":946,"content":948},{"id":947},"p_vp57yk48",[949],{"text":950,"type":82,"marks":951},"Build time only",[952],{"type":85},{"type":513,"attrs":954,"content":955},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[956],{"type":93,"attrs":957,"content":959},{"id":958},"p_0hva4zd9",[960],{"text":961,"type":82,"marks":962},"No",[963],{"type":85},{"type":513,"attrs":965,"content":966},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[967],{"type":93,"attrs":968,"content":970},{"id":969},"p_em8ctzyr",[971],{"text":972,"type":82},"Marketing pages, docs — zero dynamic content",{"type":474,"content":974},[975,986,996,1007,1017],{"type":513,"attrs":976,"content":977},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[978],{"type":93,"attrs":979,"content":981},{"id":980},"p_4n9ht249",[982],{"text":983,"type":82,"marks":984},"ISR",[985],{"type":85},{"type":513,"attrs":987,"content":988},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[989],{"type":93,"attrs":990,"content":992},{"id":991},"p_348ui4sh",[993],{"text":939,"type":82,"marks":994},[995],{"type":85},{"type":513,"attrs":997,"content":998},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[999],{"type":93,"attrs":1000,"content":1002},{"id":1001},"p_9wvso8vt",[1003],{"text":1004,"type":82,"marks":1005},"Revalidated",[1006],{"type":85},{"type":513,"attrs":1008,"content":1009},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1010],{"type":93,"attrs":1011,"content":1013},{"id":1012},"p_8i8q5qok",[1014],{"text":961,"type":82,"marks":1015},[1016],{"type":85},{"type":513,"attrs":1018,"content":1019},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1020],{"type":93,"attrs":1021,"content":1023},{"id":1022},"p_dr3q12zb",[1024],{"text":1025,"type":82},"Blog, catalog — changes predictably on a schedule",{"type":474,"content":1027},[1028,1039,1049,1060,1071],{"type":513,"attrs":1029,"content":1030},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1031],{"type":93,"attrs":1032,"content":1034},{"id":1033},"p_eynrdvz8",[1035],{"text":1036,"type":82,"marks":1037},"PPR",[1038],{"type":85},{"type":513,"attrs":1040,"content":1041},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1042],{"type":93,"attrs":1043,"content":1045},{"id":1044},"p_xfa4knq5",[1046],{"text":939,"type":82,"marks":1047},[1048],{"type":85},{"type":513,"attrs":1050,"content":1051},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1052],{"type":93,"attrs":1053,"content":1055},{"id":1054},"p_4gt4lb4o",[1056],{"text":1057,"type":82,"marks":1058},"Per request",[1059],{"type":85},{"type":513,"attrs":1061,"content":1062},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1063],{"type":93,"attrs":1064,"content":1066},{"id":1065},"p_omrkjr81",[1067],{"text":1068,"type":82,"marks":1069},"Yes (streamed)",[1070],{"type":85},{"type":513,"attrs":1072,"content":1073},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1074],{"type":93,"attrs":1075,"content":1077},{"id":1076},"p_v2fm57g3",[1078],{"text":1079,"type":82,"marks":1080},"60%+ static layout + dynamic user data — e-commerce, dashboards with public shell",[1081],{"type":85},{"type":474,"content":1083},[1084,1094,1105,1115,1126],{"type":513,"attrs":1085,"content":1086},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1087],{"type":93,"attrs":1088,"content":1090},{"id":1089},"p_72nibnjt",[1091],{"text":126,"type":82,"marks":1092},[1093],{"type":85},{"type":513,"attrs":1095,"content":1096},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1097],{"type":93,"attrs":1098,"content":1100},{"id":1099},"p_cjfss1bv",[1101],{"text":1102,"type":82,"marks":1103},"Origin latency",[1104],{"type":85},{"type":513,"attrs":1106,"content":1107},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1108],{"type":93,"attrs":1109,"content":1111},{"id":1110},"p_uc9awd2r",[1112],{"text":1057,"type":82,"marks":1113},[1114],{"type":85},{"type":513,"attrs":1116,"content":1117},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1118],{"type":93,"attrs":1119,"content":1121},{"id":1120},"p_jy91gz6y",[1122],{"text":1123,"type":82,"marks":1124},"Yes",[1125],{"type":85},{"type":513,"attrs":1127,"content":1128},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1129],{"type":93,"attrs":1130,"content":1132},{"id":1131},"p_4s042934",[1133],{"text":1134,"type":82},"Every byte is user-specific — admin panels, financial dashboards",{"type":474,"content":1136},[1137,1148,1159,1170,1180],{"type":513,"attrs":1138,"content":1139},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1140],{"type":93,"attrs":1141,"content":1143},{"id":1142},"p_bhcqongv",[1144],{"text":1145,"type":82,"marks":1146},"CSR",[1147],{"type":85},{"type":513,"attrs":1149,"content":1150},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1151],{"type":93,"attrs":1152,"content":1154},{"id":1153},"p_rizg86as",[1155],{"text":1156,"type":82,"marks":1157},"Shell instant",[1158],{"type":85},{"type":513,"attrs":1160,"content":1161},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1162],{"type":93,"attrs":1163,"content":1165},{"id":1164},"p_bwyc4p7v",[1166],{"text":1167,"type":82,"marks":1168},"Client fetch",[1169],{"type":85},{"type":513,"attrs":1171,"content":1172},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1173],{"type":93,"attrs":1174,"content":1176},{"id":1175},"p_ofaip44f",[1177],{"text":1123,"type":82,"marks":1178},[1179],{"type":85},{"type":513,"attrs":1181,"content":1182},{"align":9,"colspan":47,"rowspan":47,"colwidth":9},[1183],{"type":93,"attrs":1184,"content":1186},{"id":1185},"p_pmck77zl",[1187],{"text":1188,"type":82},"Highly interactive UI behind auth — maps, editors, complex apps",{"type":281,"attrs":1190,"content":1193},{"id":1191,"type":1192,"title":9},"call_d7q2q834","note",[1194,1202],{"type":93,"attrs":1195,"content":1197},{"id":1196},"p_rmncxbf2",[1198],{"text":1199,"type":82,"marks":1200},"→ The 60\u002F30 rule",[1201],{"type":85},{"type":93,"attrs":1203,"content":1205},{"id":1204},"p_13zu90pk",[1206,1208,1212,1214,1218],{"text":1207,"type":82},"If ",{"text":1209,"type":82,"marks":1210},"60%+ of your page is static",[1211],{"type":85},{"text":1213,"type":82},", use PPR — the gains are significant. If it's ",{"text":1215,"type":82,"marks":1216},"under 30% static",[1217],{"type":85},{"text":1219,"type":82},", stick with SSR — the overhead of splitting eats your gains. Between 30-60%, PPR still wins, but you need to aggressively cache the static portions. And if the page is 100% static — use SSG, don't add PPR complexity you don't need.",{"type":343,"attrs":1221,"content":1223},{"id":1222},"cmp_qwqldzk8",[1224,1296],{"type":348,"attrs":1225,"content":1228},{"id":1226,"side":364,"title":1227},"col_1f4mt7y1","✓ PPR is the right choice when",[1229],{"type":1230,"attrs":1231,"content":1234},"bulletList",{"id":1232,"tight":1233},"ul_w3rew3e0",true,[1235,1246,1256,1266,1276,1286],{"type":1236,"attrs":1237,"content":1239},"listItem",{"id":1238},"li_ohlmf4ko",[1240],{"type":93,"attrs":1241,"content":1243},{"id":1242},"p_209l3zrb",[1244],{"text":1245,"type":82},"- Product pages: static content + personalized sidebar, cart, recommendations",{"type":1236,"attrs":1247,"content":1249},{"id":1248},"li_cslgfw9l",[1250],{"type":93,"attrs":1251,"content":1253},{"id":1252},"p_yasio0az",[1254],{"text":1255,"type":82},"- News or blog articles with comments, user-specific ads, or reading progress",{"type":1236,"attrs":1257,"content":1259},{"id":1258},"li_qjtt6cu2",[1260],{"type":93,"attrs":1261,"content":1263},{"id":1262},"p_i59e2ukj",[1264],{"text":1265,"type":82},"- Landing pages with A\u002FB-tested elements or user-specific CTAs",{"type":1236,"attrs":1267,"content":1269},{"id":1268},"li_iljc0n1v",[1270],{"type":93,"attrs":1271,"content":1273},{"id":1272},"p_8ttkc4pt",[1274],{"text":1275,"type":82},"- Dashboard with a public shell and user-specific widgets",{"type":1236,"attrs":1277,"content":1279},{"id":1278},"li_xum0q4qs",[1280],{"type":93,"attrs":1281,"content":1283},{"id":1282},"p_rpty43l2",[1284],{"text":1285,"type":82},"- 60%+ of the page content doesn't change per user",{"type":1236,"attrs":1287,"content":1289},{"id":1288},"li_682okfzu",[1290],{"type":93,"attrs":1291,"content":1293},{"id":1292},"p_1g9ocao3",[1294],{"text":1295,"type":82},"SEO matters — static shell is immediately crawlable",{"type":348,"attrs":1297,"content":1300},{"id":1298,"side":351,"title":1299},"col_vltpz408","→ Choose a different strategy when",[1301],{"type":1230,"attrs":1302,"content":1304},{"id":1303,"tight":1233},"ul_tch6pdnv",[1305,1315,1325,1335,1345],{"type":1236,"attrs":1306,"content":1308},{"id":1307},"li_3kh6j3yp",[1309],{"type":93,"attrs":1310,"content":1312},{"id":1311},"p_es6jxbiw",[1313],{"text":1314,"type":82},"- Every byte is user-specific (financial data, admin panels) → SSR",{"type":1236,"attrs":1316,"content":1318},{"id":1317},"li_4k5tm2pp",[1319],{"type":93,"attrs":1320,"content":1322},{"id":1321},"p_x5z1v8bn",[1323],{"text":1324,"type":82},"- Content is 100% static and never personalizes → SSG or ISR",{"type":1236,"attrs":1326,"content":1328},{"id":1327},"li_blrzdq17",[1329],{"type":93,"attrs":1330,"content":1332},{"id":1331},"p_jr5ktn9t",[1333],{"text":1334,"type":82},"- Prices or inventory are in the above-fold area (stale risk) → SSR",{"type":1236,"attrs":1336,"content":1338},{"id":1337},"li_vg2mk0eb",[1339],{"type":93,"attrs":1340,"content":1342},{"id":1341},"p_6hfm9s7v",[1343],{"text":1344,"type":82},"- You're on Pages Router — PPR requires App Router",{"type":1236,"attrs":1346,"content":1348},{"id":1347},"li_m2bol1pb",[1349],{"type":93,"attrs":1350,"content":1352},{"id":1351},"p_sec93nwv",[1353],{"text":1354,"type":82},"- You need full consistency between shell and dynamic content at all times",{"type":1356,"attrs":1357},"archVisual",{"id":1358,"cards":1359,"title":9,"caption":9},"arch_jl00s4nr",[1360,1364,1368],{"tag":1361,"title":1362,"subtitle":1363},"v14","Oct 2023 — Announced at Next.js Conf.","Introduced as experimental behind experimental.ppr: true. The 'incremental' mode allowed per-route opt-in via export const experimental_ppr = true. Not stable — API subject to change.",{"tag":1365,"title":1366,"subtitle":1367},"v15","Oct 2024 — Still experimental.","Same flags, refined behavior. Vercel continued positioning PPR as not production-ready for most apps. The incremental opt-in remained the recommended way to test per route.",{"tag":1369,"title":1370,"subtitle":1371},"v16","Oct 2025 — PPR graduates to stable via Cache Components. ","experimental.ppr flag is removed. New model: cacheComponents: true in next.config.ts. The \"use cache\" directive replaces the explicit experimental_ppr route export. All code is now dynamic by default. React Compiler support promoted to stable.",{"type":281,"attrs":1373,"content":1375},{"id":1374,"type":139,"title":9},"call_y1tv0hsk",[1376,1384],{"type":93,"attrs":1377,"content":1379},{"id":1378},"p_6az2qnuc",[1380],{"text":1381,"type":82,"marks":1382},"⚠ Breaking change from v14\u002Fv15",[1383],{"type":85},{"type":93,"attrs":1385,"content":1387},{"id":1386},"p_t9q5bygk",[1388,1390,1394,1396,1400,1402,1406,1408,1412,1414,1417],{"text":1389,"type":82},"If you used ",{"text":1391,"type":82,"marks":1392},"experimental.ppr",[1393],{"type":243},{"text":1395,"type":82}," or ",{"text":1397,"type":82,"marks":1398},"experimental_ppr",[1399],{"type":243},{"text":1401,"type":82}," on Next.js 14 or 15, those flags ",{"text":1403,"type":82,"marks":1404},"no longer exist in Next.js 16",[1405],{"type":85},{"text":1407,"type":82},". Migrate to ",{"text":1409,"type":82,"marks":1410},"cacheComponents: true",[1411],{"type":243},{"text":1413,"type":82}," and the ",{"text":240,"type":82,"marks":1415},[1416],{"type":243},{"text":1418,"type":82}," directive. The behavior is the same but the configuration API changed completely.",{"type":76,"attrs":1420,"content":1422},{"id":1421,"level":36},"h_sdc3jjfo",[1423],{"text":1424,"type":82,"marks":1425},"What PPR means for how you build Next.js apps",[1426],{"type":85},{"type":93,"attrs":1428,"content":1430},{"id":1429},"p_40m839ez",[1431],{"text":1432,"type":82},"PPR doesn't replace SSR, SSG, ISR, or CSR. It coordinates with them. The rendering decision tree that defined Next.js development for years — \"is this page static or dynamic?\" — is now a component-level decision, not a route-level one.",{"type":93,"attrs":1434,"content":1436},{"id":1435},"p_7g1e7cvt",[1437,1439,1443,1445,1449],{"text":1438,"type":82},"The architectural shift is real: in Next.js 16, you stop thinking about pages as having a single rendering mode. You start thinking about ",{"text":1440,"type":82,"marks":1441},"which parts of this page are static",[1442],{"type":91},{"text":1444,"type":82}," and ",{"text":1446,"type":82,"marks":1447},"which parts need to be fresh",[1448],{"type":91},{"text":1450,"type":82},". Suspense is your boundary. The static side goes to the CDN edge and ships at edge latency. The dynamic side streams from the origin in the same HTTP response.",{"type":93,"attrs":1452,"content":1454},{"id":1453},"p_2cz171hy",[1455],{"text":1456,"type":82},"The practical outcome is that most content sites, e-commerce pages, and dashboards with a public shell and user-specific data become faster without any SSR tax. The page your user sees is the same data — it just arrives in a smarter order.",{"type":93,"attrs":1458,"content":1460},{"id":1459},"p_1mzea09b",[1461,1463,1467],{"text":1462,"type":82},"The one place to be careful: ",{"text":1464,"type":82,"marks":1465},"never put content in the static shell that users might act on before the dynamic update arrives",[1466],{"type":85},{"text":1468,"type":82},". Stale prices, stale inventory, stale discounts in the shell while the stream is still loading — that's where PPR can hurt conversion instead of helping it.",{"type":281,"attrs":1470,"content":1472},{"id":1471,"type":377,"title":9},"call_68oqx6lp",[1473,1481],{"type":93,"attrs":1474,"content":1476},{"id":1475},"p_h97pb7zz",[1477],{"text":1478,"type":82,"marks":1479},"✓ Checklist before shipping PPR",[1480],{"type":85},{"type":93,"attrs":1482,"content":1484},{"id":1483},"p_dw4652za",[1485,1489,1491,1494,1496,1500,1502,1506,1508,1511,1513,1517,1518,1522,1524,1527,1529,1533,1535,1539,1541,1545],{"text":1486,"type":82,"marks":1487},"1.",[1488],{"type":85},{"text":1490,"type":82}," Confirm ",{"text":1409,"type":82,"marks":1492},[1493],{"type":243},{"text":1495,"type":82}," in ",{"text":1497,"type":82,"marks":1498},"next.config.ts",[1499],{"type":243},{"text":1501,"type":82},". ",{"text":1503,"type":82,"marks":1504},"2.",[1505],{"type":85},{"text":1507,"type":82}," Check build output — your route should show ",{"text":268,"type":82,"marks":1509},[1510],{"type":243},{"text":1512,"type":82},", not ",{"text":1514,"type":82,"marks":1515},"λ",[1516],{"type":243},{"text":1501,"type":82},{"text":1519,"type":82,"marks":1520},"3.",[1521],{"type":85},{"text":1523,"type":82}," If it shows ",{"text":1514,"type":82,"marks":1525},[1526],{"type":243},{"text":1528,"type":82},", find the dynamic API call outside a Suspense boundary. ",{"text":1530,"type":82,"marks":1531},"4.",[1532],{"type":85},{"text":1534,"type":82}," Audit every piece of content in the static shell — would it hurt the user to see it stale? ",{"text":1536,"type":82,"marks":1537},"5.",[1538],{"type":85},{"text":1540,"type":82}," Every dynamic hole has a Suspense fallback (skeleton, not null). ",{"text":1542,"type":82,"marks":1543},"6.",[1544],{"type":85},{"text":1546,"type":82}," Test in production-like conditions — CDN caching behavior differs from local dev.",{"type":76,"attrs":1548,"content":1550},{"id":1549,"level":36},"p_lqxb4cxu",[1551],{"text":1552,"type":82,"marks":1553},"Sources — June 2026",[1554],{"type":85},{"type":1230,"attrs":1556,"content":1558},{"id":1557,"tight":1233},"ul_l6pzp3mr",[1559,1578,1598,1622,1636,1650,1669,1688],{"type":1236,"attrs":1560,"content":1562},{"id":1561},"li_65pajhhm",[1563],{"type":93,"attrs":1564,"content":1566},{"id":1565},"p_bxkefpah",[1567,1571,1573,1576],{"text":1568,"type":82,"marks":1569},"nextjs.org\u002Fblog\u002Fnext-16 (Oct 2025)",[1570],{"type":85},{"text":1572,"type":82}," — Official Next.js 16 release notes: Cache Components, PPR stable, ",{"text":1409,"type":82,"marks":1574},[1575],{"type":243},{"text":1577,"type":82},", React Compiler stable, Turbopack stable.",{"type":1236,"attrs":1579,"content":1581},{"id":1580},"li_xjeo8fmn",[1582],{"type":93,"attrs":1583,"content":1585},{"id":1584},"p_elntwzvj",[1586,1590,1592,1596],{"text":1587,"type":82,"marks":1588},"nextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fppr-platform-guide (Mar 2026)",[1589],{"type":85},{"text":1591,"type":82}," — Platform guide: static shell, ",{"text":1593,"type":82,"marks":1594},"postponedState",[1595],{"type":243},{"text":1597,"type":82},", CDN resume protocol, streaming architecture.",{"type":1236,"attrs":1599,"content":1601},{"id":1600},"li_o7fuhv66",[1602],{"type":93,"attrs":1603,"content":1605},{"id":1604},"p_08ubf0yw",[1606,1610,1612,1615,1617,1620],{"text":1607,"type":82,"marks":1608},"nextjs.org\u002Fdocs\u002F15\u002Fapp\u002Fgetting-started\u002Fpartial-prerendering (Aug 2025)",[1609],{"type":85},{"text":1611,"type":82}," — Getting started guide: ",{"text":1397,"type":82,"marks":1613},[1614],{"type":243},{"text":1616,"type":82},", Suspense boundaries, ",{"text":240,"type":82,"marks":1618},[1619],{"type":243},{"text":1621,"type":82}," directive.",{"type":1236,"attrs":1623,"content":1625},{"id":1624},"li_cg5d403p",[1626],{"type":93,"attrs":1627,"content":1629},{"id":1628},"p_d0p59tdy",[1630,1634],{"text":1631,"type":82,"marks":1632},"PageGlass (Apr 27, 2026)",[1633],{"type":85},{"text":1635,"type":82}," — \"Partial Prerendering: A Practical Guide (2026)\" — PPR vs streaming SSR, CDN caching, App Router requirement, 60\u002F30 rule.",{"type":1236,"attrs":1637,"content":1639},{"id":1638},"li_4kc1f5qj",[1640],{"type":93,"attrs":1641,"content":1643},{"id":1642},"p_movf1xy3",[1644,1648],{"text":1645,"type":82,"marks":1646},"TheCodeForge (Apr 11, 2026)",[1647],{"type":85},{"text":1649,"type":82}," — \"Partial Prerendering in Next.js 16\" — production pitfalls, 12% conversion drop case study, strategy matrix, PPR + ISR composition.",{"type":1236,"attrs":1651,"content":1653},{"id":1652},"li_2pmecw6q",[1654],{"type":93,"attrs":1655,"content":1657},{"id":1656},"p_6phco2mj",[1658,1662,1664,1667],{"text":1659,"type":82,"marks":1660},"DEV Community \u002F Pockit (Mar 18, 2026)",[1661],{"type":85},{"text":1663,"type":82}," — \"Next.js PPR Deep Dive\" — ",{"text":268,"type":82,"marks":1665},[1666],{"type":243},{"text":1668,"type":82}," build output indicator, debugging fully-dynamic pages, migration patterns.",{"type":1236,"attrs":1670,"content":1672},{"id":1671},"li_jv4smdli",[1673],{"type":93,"attrs":1674,"content":1676},{"id":1675},"p_tbw0iwlt",[1677,1681,1683,1686],{"text":1678,"type":82,"marks":1679},"Ashish Gogula (Dec 4, 2025)",[1680],{"type":85},{"text":1682,"type":82}," — \"A Practical Guide to PPR in Next.js 16\" — ",{"text":1409,"type":82,"marks":1684},[1685],{"type":243},{"text":1687,"type":82}," config, demo project, Suspense + skeleton pattern.",{"type":1236,"attrs":1689,"content":1691},{"id":1690},"li_hdmx2pao",[1692],{"type":93,"attrs":1693,"content":1695},{"id":1694},"p_2hau9xk0",[1696,1700,1702,1705],{"text":1697,"type":82,"marks":1698},"U11D (Feb 13, 2026)",[1699],{"type":85},{"text":1701,"type":82}," — \"Next.js 16 PPR: Best of Static and Dynamic Rendering\" — e-commerce use case, ",{"text":240,"type":82,"marks":1703},[1704],{"type":243},{"text":1706,"type":82}," directive, comparison with SSG\u002FISR.",{"type":1708},"horizontalRule",{"type":93,"attrs":1710,"content":1712},{"id":1711},"p_5vzsnq7e",[1713,1715,1718,1720,1723,1725,1728],{"text":1714,"type":82},"Code examples reflect Next.js 16 (October 2025) stable API. The ",{"text":1391,"type":82,"marks":1716},[1717],{"type":243},{"text":1719,"type":82}," flag and ",{"text":1397,"type":82,"marks":1721},[1722],{"type":243},{"text":1724,"type":82}," route export were removed in Next.js 16 — do not use them in new projects. ",{"text":1409,"type":82,"marks":1726},[1727],{"type":243},{"text":1729,"type":82}," is the stable API. PPR requires the App Router — it is not available on the Pages Router. Always verify behavior with your CDN provider, as edge caching behavior for PPR routes varies by platform.","Next.js PPR: The End of the Static vs. Dynamic Tradeoff","Learn how Partial Prerendering in Next.js 16 eliminates the choice between static speed and dynamic data by combining both in a single response.","2026-08-24T14:53:53.315534+00:00",[1734,1759,1777,1791],{"id":1735,"slug":1736,"title":1737,"excerpt":1738,"image":1739,"featured":1233,"groupId":1740,"publishedAt":1741,"readingTime":1742,"views":1743,"author":1744,"category":1745,"tags":1746},"81f24e9a-fc6b-47d0-beb9-d00a6137ed99","framework-vs-sdk-who-calls-whom","Framework vs SDK: Who Calls Whom","Most developers memorize names, but few understand the mechanism. Here is the simple rule to tell a framework from an SDK and level up your debugging.","https:\u002F\u002Fmfgiomkkbihnlpfdxwrt.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fblog-assets\u002Fmedia\u002Ffeatured\u002F1787491947099-featured-ikba2e.jpg","0ccb21eb-6459-40ed-8110-227836e9bb74","2026-08-23T13:15:25.439194+00:00",10,0,{"name":49,"avatar":9},{"slug":13,"name":14,"color":15},[1747,1750,1753,1756],{"slug":1748,"name":1749},"javascript","JavaScript",{"slug":1751,"name":1752},"python","Python",{"slug":1754,"name":1755},"runtime","Runtime",{"slug":1757,"name":1758},"sdk","Sdk",{"id":1760,"slug":1761,"title":1762,"excerpt":1763,"image":1764,"featured":44,"groupId":1765,"publishedAt":1766,"readingTime":1767,"views":1768,"author":1769,"category":1770,"tags":1771},"c2d6b1ca-29bf-401f-8ab9-a1f828504d0b","microfrontends-with-angular-and-nx-what-nobody-tells-you","Microfrontends with Angular and Nx: what nobody tells you","Every tutorial teaches how to set up microfrontends in minutes, but few reveal the architectural chaos that emerges after months of production deploys.","https:\u002F\u002Fmfgiomkkbihnlpfdxwrt.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fblog-assets\u002Fmedia\u002Ffeatured\u002F1785206853570-featured-zoyhgn.webp","3368e1b2-b6de-4e94-a3d4-294fae8ade13","2026-08-03T01:42:48.969355+00:00",15,5,{"name":49,"avatar":9},{"slug":13,"name":14,"color":15},[1772,1775,1776],{"slug":1773,"name":1774},"angular","Angular",{"slug":1748,"name":1749},{"slug":59,"name":60},{"id":1778,"slug":1779,"title":1780,"excerpt":1781,"image":1782,"featured":44,"groupId":1783,"publishedAt":1784,"readingTime":1785,"views":1742,"author":1786,"category":1787,"tags":1788},"36440333-311c-4081-92e6-030a04a38fed","astro-island-architecture-performance-and-where-the-framework-truly-fits","Astro: Island Architecture, Performance, and Where the Framework Truly Fits","Astro challenges the modern web status quo by prioritizing static HTML and isolating interactivity into independent, lightweight code islands.","https:\u002F\u002Fmfgiomkkbihnlpfdxwrt.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fblog-assets\u002Fmedia\u002Ffeatured\u002F1785721161920-featured-a5vzkb.webp","cb62459e-7ace-43d3-a545-661c5695e925","2026-08-03T01:00:45.280114+00:00",38,{"name":49,"avatar":9},{"slug":13,"name":14,"color":15},[1789,1790],{"slug":1748,"name":1749},{"slug":59,"name":60},{"id":1792,"slug":1793,"title":1794,"excerpt":1795,"image":1796,"featured":44,"groupId":1797,"publishedAt":1798,"readingTime":1799,"views":1743,"author":1800,"category":1801,"tags":1802},"633b6488-2a90-4632-86a5-9cff7ed52f08","javascript-event-loop-the-heart-of-non-blocking-concurrency-revisited-in-2025","JavaScript Event Loop: The Heart of Non-Blocking Concurrency — Revisited in 2025","The Event Loop is not just a simple loop, but a sophisticated coordination mechanism between Call Stack, queues, and runtime. Essential for JS concurrency, it enables thousands of asynchronous operations without blocking the UI. This guide explores its structure, differences between Node.js and browsers, common bugs, advanced techniques, and 2025 trends like Structured Concurrency and scheduler.yield().","https:\u002F\u002Fmfgiomkkbihnlpfdxwrt.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fblog-assets\u002Fmedia\u002Ffeatured\u002F1772847201637-featured-oreiro.jpeg","df6ca967-8130-4b2d-bcac-3532a150131e","2026-07-26T18:54:25.359533+00:00",6,{"name":49,"avatar":9},{"slug":13,"name":14,"color":15},[1803,1804],{"slug":1748,"name":1749},{"slug":1805,"name":1806},"nodejs","Node.js",{"pt":1808,"en":40},"next-js-16-ppr-elimine-o-tradeoff-entre-estatico-e-dinamico-e-alcance-edge-ttfb"]