[{"data":1,"prerenderedAt":898},["ShallowReactive",2],{"content:\u002Fnetwork-protocol-optimization\u002Fstreaming-ssr-and-early-flush\u002Fflushing-the-document-head-early":3,"surroundings:\u002Fnetwork-protocol-optimization\u002Fstreaming-ssr-and-early-flush\u002Fflushing-the-document-head-early":890},{"id":4,"title":5,"body":6,"description":869,"extension":870,"meta":871,"navigation":883,"path":884,"seo":885,"stem":888,"__hash__":889},"content\u002Fnetwork-protocol-optimization\u002Fstreaming-ssr-and-early-flush\u002Fflushing-the-document-head-early\u002Findex.md","Flushing the Document Head Early",{"type":7,"value":8,"toc":852},"minimark",[9,14,29,37,136,141,174,178,184,190,196,202,206,211,214,218,289,341,345,348,352,355,480,484,491,495,506,510,521,652,656,682,686,692,698,704,710,714,726,738,747,756,765,774,783,792,801,810,814,837,842,845,848],[10,11,13],"h1",{"id":12},"how-to-flush-the-document-head-early","How to Flush the Document Head Early",[15,16,17,18,23,24,28],"p",{},"This guide is part of ",[19,20,22],"a",{"href":21},"\u002Fnetwork-protocol-optimization\u002Fstreaming-ssr-and-early-flush\u002F","Streaming SSR & Early Flush",", within ",[19,25,27],{"href":26},"\u002Fnetwork-protocol-optimization\u002F","Network & Server Response Optimization",". The document head is almost always the same regardless of the data on the page: the same stylesheet, the same fonts, the same scripts, often a predictable LCP image (a product hero, an article header). Yet servers usually wait until all data is loaded and the whole page is rendered before sending even the first byte of the head. During that time, the browser has an open connection and nothing to do.",[15,30,31,32,36],{},"Early flush sends the head — ",[33,34,35],"code",{},"\u003C!doctype html>",", meta tags, stylesheet links, font preloads, preconnects, and an LCP image preload when its URL is known — immediately, then does the slow work and sends the body. It works in any server stack that can write a response in parts: Node.js, PHP, Python, Ruby, Go, Java. It is the highest-value, lowest-complexity form of streaming.",[15,38,39],{},[40,41,47,48,47,55,47,59,47,62,47,71,47,77,47,84,47,92,47,97,47,101,47,105,47,109,47,113,47,120,47,124,47,128,47,132,47],"svg",{"viewBox":42,"width":43,"role":44,"ariaLabel":45,"style":46},"0 0 760 194","100%","img","Bar chart comparing when the stylesheet and LCP image start downloading with and without early head flush.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[49,50],"rect",{"className":51,"x":53,"y":53,"width":43,"height":43,"fill":54},[52],"svg-canvas","0","#ffffff",[56,57,58],"title",{},"Time until critical downloads start (uncached page)",[60,61,45],"desc",{},[49,63],{"x":64,"y":64,"width":65,"height":66,"rx":67,"fill":68,"stroke":69,"style":70},"1","758","192","10","none","currentColor","stroke-opacity:0.18",[72,73,58],"text",{"x":74,"y":75,"fill":69,"style":76},"28.0","34.0","font-size:16px;font-weight:700",[72,78,83],{"x":79,"y":80,"fill":69,"style":81,"textAnchor":82},"212.2","70.0","font-size:13px","end","Buffered - CSS request starts",[49,85],{"x":86,"y":87,"width":88,"height":89,"rx":90,"fill":68,"stroke":69,"style":91},"224.2","56.0","394.0","19","3","fill-opacity:0.7;stroke-opacity:0.35",[72,93,96],{"x":94,"y":80,"fill":69,"style":95},"624.2","font-size:12px;font-weight:600","870ms",[72,98,100],{"x":79,"y":99,"fill":69,"style":81,"textAnchor":82},"101.0","Buffered - LCP image starts",[49,102],{"x":86,"y":103,"width":104,"height":89,"rx":90,"fill":68,"stroke":69,"style":91},"87.0","443.8",[72,106,108],{"x":107,"y":99,"fill":69,"style":95},"674.0","980ms",[72,110,112],{"x":79,"y":111,"fill":69,"style":81,"textAnchor":82},"132.0","Early flush - CSS request starts",[49,114],{"x":86,"y":115,"width":116,"height":89,"rx":90,"fill":117,"stroke":118,"style":119},"118.0","54.3","#ffc300","#b8860b","fill-opacity:0.7;stroke-opacity:0.9",[72,121,123],{"x":122,"y":111,"fill":69,"style":95},"284.5","120ms",[72,125,127],{"x":79,"y":126,"fill":69,"style":81,"textAnchor":82},"163.0","Early flush - LCP image starts",[49,129],{"x":86,"y":130,"width":131,"height":89,"rx":90,"fill":117,"stroke":118,"style":119},"149.0","58.9",[72,133,135],{"x":134,"y":126,"fill":69,"style":95},"289.1","130ms",[137,138,140],"h2",{"id":139},"rapid-diagnosis","Rapid Diagnosis",[142,143,144,152,158,164],"ul",{},[145,146,147,151],"li",{},[148,149,150],"strong",{},"Compare TTFB with server time",": if TTFB roughly equals total server time, nothing is flushed early.",[145,153,154,157],{},[148,155,156],{},"Check when the stylesheet request starts"," in the waterfall: right after the HTML finishes means no early flush.",[145,159,160,163],{},[148,161,162],{},"Check server code"," for template rendering that returns a full string.",[145,165,166,169,170,173],{},[148,167,168],{},"Check output buffering"," settings (PHP ",[33,171,172],{},"output_buffering",", framework response buffering).",[137,175,177],{"id":176},"root-cause-analysis","Root Cause Analysis",[15,179,180,183],{},[148,181,182],{},"1. Render-then-send templates."," Most templating returns a complete string.",[15,185,186,189],{},[148,187,188],{},"2. Output buffering."," Language runtimes or frameworks buffer by default.",[15,191,192,195],{},[148,193,194],{},"3. Status codes decided late."," Code paths decide 404 or redirects after data loads.",[15,197,198,201],{},[148,199,200],{},"4. Head contents depend on data."," Titles and meta descriptions need data, discouraging early flush.",[137,203,205],{"id":204},"step-by-step-resolution","Step-by-Step Resolution",[207,208,210],"h3",{"id":209},"_1-split-the-template-into-head-and-body","1. Split the template into head and body",[15,212,213],{},"Render a head template that depends only on request-level information (route, locale) and maybe a fast lookup for the title.",[207,215,217],{"id":216},"_2-flush-the-head-before-slow-work","2. Flush the head before slow work",[219,220,225],"pre",{"className":221,"code":222,"language":223,"meta":224,"style":224},"language-php shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u003C?php\n\u002F\u002F PHP: flush the head before database work.\nheader('Content-Type: text\u002Fhtml; charset=utf-8');\necho render_head(['css' => '\u002Fcss\u002Fapp.4f2a.css', 'lcp' => \"\u002Fimg\u002F{$id}-1200.avif\"]);\nif (function_exists('ob_get_level')) { while (ob_get_level() > 0) ob_end_flush(); }\nflush();                                           \u002F\u002F send the head now\n$product = load_product($id);                      \u002F\u002F slow work afterwards\necho render_body($product);\n\u002F\u002F trade-off: output buffering at several layers (PHP-FPM, web server, gzip) can\n\u002F\u002F still hold the bytes; verify with curl timing in production.\n","php","",[33,226,227,235,241,247,253,259,265,271,277,283],{"__ignoreMap":224},[228,229,232],"span",{"class":230,"line":231},"line",1,[228,233,234],{},"\u003C?php\n",[228,236,238],{"class":230,"line":237},2,[228,239,240],{},"\u002F\u002F PHP: flush the head before database work.\n",[228,242,244],{"class":230,"line":243},3,[228,245,246],{},"header('Content-Type: text\u002Fhtml; charset=utf-8');\n",[228,248,250],{"class":230,"line":249},4,[228,251,252],{},"echo render_head(['css' => '\u002Fcss\u002Fapp.4f2a.css', 'lcp' => \"\u002Fimg\u002F{$id}-1200.avif\"]);\n",[228,254,256],{"class":230,"line":255},5,[228,257,258],{},"if (function_exists('ob_get_level')) { while (ob_get_level() > 0) ob_end_flush(); }\n",[228,260,262],{"class":230,"line":261},6,[228,263,264],{},"flush();                                           \u002F\u002F send the head now\n",[228,266,268],{"class":230,"line":267},7,[228,269,270],{},"$product = load_product($id);                      \u002F\u002F slow work afterwards\n",[228,272,274],{"class":230,"line":273},8,[228,275,276],{},"echo render_body($product);\n",[228,278,280],{"class":230,"line":279},9,[228,281,282],{},"\u002F\u002F trade-off: output buffering at several layers (PHP-FPM, web server, gzip) can\n",[228,284,286],{"class":230,"line":285},10,[228,287,288],{},"\u002F\u002F still hold the bytes; verify with curl timing in production.\n",[219,290,294],{"className":291,"code":292,"language":293,"meta":224,"style":224},"language-python shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","# Python (Flask): stream a generator that yields the head first.\nfrom flask import Response, stream_with_context\n@app.route('\u002Farticle\u002F\u003Cslug>')\ndef article(slug):\n    def gen():\n        yield render_template('head.html', css=CSS_URL)\n        data = load_article(slug)                  # slow\n        yield render_template('body.html', article=data)\n    return Response(stream_with_context(gen()), mimetype='text\u002Fhtml')\n","python",[33,295,296,301,306,311,316,321,326,331,336],{"__ignoreMap":224},[228,297,298],{"class":230,"line":231},[228,299,300],{},"# Python (Flask): stream a generator that yields the head first.\n",[228,302,303],{"class":230,"line":237},[228,304,305],{},"from flask import Response, stream_with_context\n",[228,307,308],{"class":230,"line":243},[228,309,310],{},"@app.route('\u002Farticle\u002F\u003Cslug>')\n",[228,312,313],{"class":230,"line":249},[228,314,315],{},"def article(slug):\n",[228,317,318],{"class":230,"line":255},[228,319,320],{},"    def gen():\n",[228,322,323],{"class":230,"line":261},[228,324,325],{},"        yield render_template('head.html', css=CSS_URL)\n",[228,327,328],{"class":230,"line":267},[228,329,330],{},"        data = load_article(slug)                  # slow\n",[228,332,333],{"class":230,"line":273},[228,334,335],{},"        yield render_template('body.html', article=data)\n",[228,337,338],{"class":230,"line":279},[228,339,340],{},"    return Response(stream_with_context(gen()), mimetype='text\u002Fhtml')\n",[207,342,344],{"id":343},"_3-decide-status-codes-before-flushing","3. Decide status codes before flushing",[15,346,347],{},"Do a fast existence check (cache lookup or a primary-key query) before sending the head. If the resource does not exist or requires a redirect, respond normally without streaming.",[207,349,351],{"id":350},"_4-resolve-title-and-meta-quickly-or-update-later","4. Resolve title and meta quickly or update later",[15,353,354],{},"Use a fast lookup for the title and description, or emit a generic title and set a more specific one during rendering (search engines use the final DOM). Social preview metadata should be correct in the HTML; for those, fetch it before flushing.",[15,356,357],{},[40,358,47,361,47,364,47,367,47,369,47,386,47,389,47,391,47,398,47,405,47,410,47,413,47,417,47,421,47,425,47,429,47,433,47,436,47,440,47,443,47,447,47,450,47,453,47,457,47,460,47,468,47,472,47,476,47],{"viewBox":359,"width":43,"role":44,"ariaLabel":360,"style":46},"0 0 760 150","Order of operations for a request handled with early head flush.",[49,362],{"className":363,"x":53,"y":53,"width":43,"height":43,"fill":54},[52],[56,365,366],{},"Request flow with early flush",[60,368,360],{},[370,371,372],"defs",{},[373,374,381],"marker",{"id":375,"viewBox":376,"refX":377,"refY":378,"markerWidth":379,"markerHeight":379,"orient":380},"fa7dcb356e","0 0 10 10","9","5","7","auto-start-reverse",[382,383],"path",{"d":384,"fill":69,"style":385},"M0 0 L10 5 L0 10 z","fill-opacity:0.7",[49,387],{"x":64,"y":64,"width":65,"height":388,"rx":67,"fill":68,"stroke":69,"style":70},"148",[72,390,366],{"x":74,"y":75,"fill":69,"style":76},[49,392],{"x":74,"y":87,"width":393,"height":394,"rx":395,"fill":396,"stroke":396,"style":397},"108.8","72.0","6","#0466c8","fill-opacity:0.14;stroke-opacity:0.9",[72,399,404],{"x":400,"y":401,"fill":69,"style":402,"textAnchor":403},"82.4","78.0","font-size:13px;font-weight:700","middle","Route + exists?",[72,406,409],{"x":400,"y":407,"fill":69,"style":408,"textAnchor":403},"96.0","font-size:12px","fast check",[49,411],{"x":412,"y":87,"width":393,"height":394,"rx":395,"fill":396,"stroke":396,"style":397},"176.8",[72,414,416],{"x":415,"y":401,"fill":69,"style":402,"textAnchor":403},"231.2","Status +",[72,418,420],{"x":415,"y":419,"fill":69,"style":402,"textAnchor":403},"95.0","headers",[72,422,424],{"x":415,"y":423,"fill":69,"style":408,"textAnchor":403},"113.0","decided now",[49,426],{"x":427,"y":87,"width":393,"height":394,"rx":395,"fill":117,"stroke":118,"style":428},"325.6","fill-opacity:0.24;stroke-opacity:0.9",[72,430,432],{"x":431,"y":401,"fill":69,"style":402,"textAnchor":403},"380.0","Flush head",[72,434,435],{"x":431,"y":407,"fill":69,"style":408,"textAnchor":403},"CSS, preload,",[72,437,439],{"x":431,"y":438,"fill":69,"style":408,"textAnchor":403},"112.0","preconnect",[49,441],{"x":442,"y":87,"width":393,"height":394,"rx":395,"fill":396,"stroke":396,"style":397},"474.4",[72,444,446],{"x":445,"y":401,"fill":69,"style":402,"textAnchor":403},"528.8","Slow work",[72,448,449],{"x":445,"y":407,"fill":69,"style":408,"textAnchor":403},"queries, APIs",[49,451],{"x":452,"y":87,"width":393,"height":394,"rx":395,"fill":396,"stroke":396,"style":397},"623.2",[72,454,456],{"x":455,"y":401,"fill":69,"style":402,"textAnchor":403},"677.6","Body",[72,458,459],{"x":455,"y":407,"fill":69,"style":408,"textAnchor":403},"render + send",[230,461],{"x1":462,"y1":463,"x2":464,"y2":463,"stroke":69,"strokeWidth":465,"style":466,"markerEnd":467},"136.8","92.0","174.8","1.5","stroke-opacity:0.6","url(#fa7dcb356e)",[230,469],{"x1":470,"y1":463,"x2":471,"y2":463,"stroke":69,"strokeWidth":465,"style":466,"markerEnd":467},"285.6","323.6",[230,473],{"x1":474,"y1":463,"x2":475,"y2":463,"stroke":69,"strokeWidth":465,"style":466,"markerEnd":467},"434.4","472.4",[230,477],{"x1":478,"y1":463,"x2":479,"y2":463,"stroke":69,"strokeWidth":465,"style":466,"markerEnd":467},"583.2","621.2",[137,481,483],{"id":482},"verification","Verification",[15,485,486,487,490],{},"Use ",[33,488,489],{},"curl -sN"," with timestamps to confirm the head arrives before the body. In DevTools, the stylesheet and LCP image requests should start long before the document finishes downloading. Compare LCP for uncached requests before and after.",[137,492,494],{"id":493},"worked-example-a-wordpress-news-site","Worked Example: A WordPress News Site",[15,496,497,498,501,502,505],{},"A WordPress-based news site had uncached TTFB around 700ms because of plugins and database queries, with the theme rendering the full page before output. The team modified the theme to output the head (stylesheet, font preloads, a preload of the featured image computed from the post ID with a fast lookup) and call ",[33,499,500],{},"flush()"," before the main loop ran. They disabled an output-buffering plugin and set ",[33,503,504],{},"fastcgi_buffering off"," for HTML routes in nginx. The stylesheet and featured image now started downloading about 600ms earlier; LCP p75 for uncached article views improved from 2.7 to 2.1 seconds.",[137,507,509],{"id":508},"what-belongs-in-the-flushed-head","What Belongs in the Flushed Head",[15,511,512,513,516,517,520],{},"Include everything the browser needs to start critical work: ",[33,514,515],{},"\u003Cmeta charset>"," and viewport, the main stylesheet (or inlined critical CSS), preloads for the main font files (with ",[33,518,519],{},"crossorigin","), a preload for the LCP image if its URL is predictable, preconnects to critical third-party origins, and module or deferred scripts. Avoid synchronous third-party scripts — they block parsing of the rest of the stream. If the LCP image is not predictable from the route, flush the head anyway; the stylesheet and fonts alone justify it, and the image will be discovered as soon as the body chunk containing it arrives.",[15,522,523],{},[40,524,47,527,47,530,47,533,47,535,47,538,47,540,47,545,47,552,47,556,47,560,47,563,47,567,47,571,47,575,47,577,47,580,47,582,47,585,47,588,47,592,47,594,47,596,47,598,47,601,47,604,47,608,47,610,47,613,47,615,47,618,47,621,47,625,47,627,47,630,47,632,47,635,47,638,47,642,47,644,47,647,47,649,47],{"viewBox":525,"width":43,"role":44,"ariaLabel":526,"style":46},"0 0 760 258","Elements to include or avoid in an early-flushed document head.",[49,528],{"className":529,"x":53,"y":53,"width":43,"height":43,"fill":54},[52],[56,531,532],{},"What to put in the early head",[60,534,526],{},[49,536],{"x":64,"y":64,"width":65,"height":537,"rx":67,"fill":68,"stroke":69,"style":70},"256",[72,539,532],{"x":74,"y":75,"fill":69,"style":76},[49,541],{"x":74,"y":87,"width":542,"height":543,"rx":53,"fill":69,"stroke":69,"style":544},"185.8","30.0","fill-opacity:0.06;stroke-opacity:0.4",[72,546,551],{"x":547,"y":548,"fill":69,"style":549,"textAnchor":550},"38.0","75.5","font-size:12.5px;font-weight:700","start","Element",[49,553],{"x":554,"y":87,"width":555,"height":543,"rx":53,"fill":69,"stroke":69,"style":544},"213.8","259.1",[72,557,559],{"x":558,"y":548,"fill":69,"style":549,"textAnchor":403},"343.4","Include?",[49,561],{"x":562,"y":87,"width":555,"height":543,"rx":53,"fill":69,"stroke":69,"style":544},"472.9",[72,564,566],{"x":565,"y":548,"fill":69,"style":549,"textAnchor":403},"602.5","Why",[49,568],{"x":74,"y":569,"width":542,"height":543,"rx":53,"fill":68,"stroke":69,"style":570},"86.0","stroke-opacity:0.35",[72,572,574],{"x":547,"y":573,"fill":69,"style":549,"textAnchor":550},"105.5","Stylesheet \u002F critical CSS",[49,576],{"x":554,"y":569,"width":555,"height":543,"rx":53,"fill":396,"stroke":396,"style":397},[72,578,579],{"x":558,"y":573,"fill":69,"style":408,"textAnchor":403},"yes",[49,581],{"x":562,"y":569,"width":555,"height":543,"rx":53,"fill":68,"stroke":69,"style":570},[72,583,584],{"x":565,"y":573,"fill":69,"style":408,"textAnchor":403},"starts the render-blocking download",[49,586],{"x":74,"y":587,"width":542,"height":543,"rx":53,"fill":68,"stroke":69,"style":570},"116.0",[72,589,591],{"x":547,"y":590,"fill":69,"style":549,"textAnchor":550},"135.5","Font preloads",[49,593],{"x":554,"y":587,"width":555,"height":543,"rx":53,"fill":396,"stroke":396,"style":397},[72,595,579],{"x":558,"y":590,"fill":69,"style":408,"textAnchor":403},[49,597],{"x":562,"y":587,"width":555,"height":543,"rx":53,"fill":68,"stroke":69,"style":570},[72,599,600],{"x":565,"y":590,"fill":69,"style":408,"textAnchor":403},"fonts discovered late otherwise",[49,602],{"x":74,"y":603,"width":542,"height":543,"rx":53,"fill":68,"stroke":69,"style":570},"146.0",[72,605,607],{"x":547,"y":606,"fill":69,"style":549,"textAnchor":550},"165.5","LCP image preload",[49,609],{"x":554,"y":603,"width":555,"height":543,"rx":53,"fill":396,"stroke":396,"style":397},[72,611,612],{"x":558,"y":606,"fill":69,"style":408,"textAnchor":403},"if URL known",[49,614],{"x":562,"y":603,"width":555,"height":543,"rx":53,"fill":68,"stroke":69,"style":570},[72,616,617],{"x":565,"y":606,"fill":69,"style":408,"textAnchor":403},"starts the LCP download early",[49,619],{"x":74,"y":620,"width":542,"height":543,"rx":53,"fill":68,"stroke":69,"style":570},"176.0",[72,622,624],{"x":547,"y":623,"fill":69,"style":549,"textAnchor":550},"195.5","Preconnect to critical origins",[49,626],{"x":554,"y":620,"width":555,"height":543,"rx":53,"fill":396,"stroke":396,"style":397},[72,628,629],{"x":558,"y":623,"fill":69,"style":408,"textAnchor":403},"1-3",[49,631],{"x":562,"y":620,"width":555,"height":543,"rx":53,"fill":68,"stroke":69,"style":570},[72,633,634],{"x":565,"y":623,"fill":69,"style":408,"textAnchor":403},"warms connections",[49,636],{"x":74,"y":637,"width":542,"height":543,"rx":53,"fill":68,"stroke":69,"style":570},"206.0",[72,639,641],{"x":547,"y":640,"fill":69,"style":549,"textAnchor":550},"225.5","Sync third-party scripts",[49,643],{"x":554,"y":637,"width":555,"height":543,"rx":53,"fill":117,"stroke":118,"style":428},[72,645,646],{"x":558,"y":640,"fill":69,"style":408,"textAnchor":403},"no",[49,648],{"x":562,"y":637,"width":555,"height":543,"rx":53,"fill":68,"stroke":69,"style":570},[72,650,651],{"x":565,"y":640,"fill":69,"style":408,"textAnchor":403},"block parsing of the stream",[137,653,655],{"id":654},"common-mistakes","Common Mistakes",[142,657,658,664,670,676],{},[145,659,660,663],{},[148,661,662],{},"Buffering somewhere downstream."," The code flushes, but the bytes do not leave the server.",[145,665,666,669],{},[148,667,668],{},"Flushing before deciding status."," A 200 for a missing page.",[145,671,672,675],{},[148,673,674],{},"Synchronous scripts in the head."," Block parsing of streamed body content.",[145,677,678,681],{},[148,679,680],{},"Flushing tiny amounts with compression."," Compressors may hold small chunks; flush the compressor too.",[137,683,685],{"id":684},"edge-cases","Edge Cases",[15,687,688,691],{},[148,689,690],{},"Personalised heads."," If the head varies per user (CSRF tokens, user-specific preloads), it can still be flushed early as long as it is computed quickly.",[15,693,694,697],{},[148,695,696],{},"Caching."," Early-flushed responses can be cached at the CDN; cached responses are served in full immediately.",[15,699,700,703],{},[148,701,702],{},"HTTP\u002F1.1 clients."," Streaming works over chunked transfer encoding on HTTP\u002F1.1 and natively over HTTP\u002F2 and HTTP\u002F3.",[15,705,706,709],{},[148,707,708],{},"Early Hints."," 103 Early Hints can deliver preloads even before the head; the two techniques combine well.",[137,711,713],{"id":712},"faq","FAQ",[715,716,719,723],"details",{"className":717},[718],"faq-item",[720,721,722],"summary",{},"What is the benefit of flushing the head early?",[15,724,725],{},"The browser starts downloading CSS, fonts and the LCP image while the server is still generating the page, overlapping network and server time.",[715,727,729,732],{"className":728},[718],[720,730,731],{},"Does early flush work with PHP?",[15,733,734,735,737],{},"Yes, with ",[33,736,500],{}," after disabling output buffering, and making sure the web server and FastCGI layer do not buffer.",[715,739,741,744],{"className":740},[718],[720,742,743],{},"Is early flush the same as Early Hints?",[15,745,746],{},"No. Early Hints is a separate 103 response with Link headers sent before the final response. Early flush sends the start of the actual HTML. They complement each other.",[715,748,750,753],{"className":749},[718],[720,751,752],{},"Can I flush if my title depends on data?",[15,754,755],{},"Yes, with a fast title lookup before flushing, or by flushing everything except the title-dependent tags. Most of the gain comes from stylesheet and preload hints.",[715,757,759,762],{"className":758},[718],[720,760,761],{},"Does early flush affect caching?",[15,763,764],{},"No. Responses can still be cached; caches store the full response.",[715,766,768,771],{"className":767},[718],[720,769,770],{},"How do I know if my server buffers?",[15,772,773],{},"Measure with curl and timestamps, or compare TTFB with server processing time. If TTFB includes all server time, something buffers.",[715,775,777,780],{"className":776},[718],[720,778,779],{},"Does early flush help pages served from CDN cache?",[15,781,782],{},"Little. Cached responses arrive quickly in full anyway. Early flush helps uncached, server-rendered responses.",[715,784,786,789],{"className":785},[718],[720,787,788],{},"Should I flush the header and navigation too?",[15,790,791],{},"If they render without slow data, yes — flushing a visible shell lets the browser paint it early, improving FCP.",[715,793,795,798],{"className":794},[718],[720,796,797],{},"Will flushing early break my layout or scripts?",[15,799,800],{},"Not if the head is complete and valid on its own. Scripts in the head should be deferred or modules, so they run after the full document has been parsed regardless of when it arrives.",[715,802,804,807],{"className":803},[718],[720,805,806],{},"What if my framework buffers responses?",[15,808,809],{},"Check whether it has a streaming mode; most modern frameworks do. If not, a small custom server route for key templates can flush the head before handing off to the framework renderer.",[137,811,813],{"id":812},"related","Related",[142,815,816,823,830],{},[145,817,818,822],{},[19,819,821],{"href":820},"\u002Fnetwork-protocol-optimization\u002Fstreaming-ssr-and-early-flush\u002Fstreaming-ssr-with-react-suspense\u002F","Streaming SSR with React Suspense"," — framework-level streaming.",[145,824,825,829],{},[19,826,828],{"href":827},"\u002Fnetwork-protocol-optimization\u002Fstreaming-ssr-and-early-flush\u002Fstreaming-html-through-cdns-and-proxies\u002F","Streaming HTML through CDNs and proxies"," — making sure flushes reach the browser.",[145,831,832,836],{},[19,833,835],{"href":834},"\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002F","Resource hints & Early Hints"," — the hints that belong in the flushed head.",[838,839,841],"script",{"type":840},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"How to Flush the Document Head Early\",\n  \"description\": \"The simplest form of streaming: send the document head with critical resource hints before the server does slow work, in any server stack.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Split the template into head and body\",\n      \"text\": \"Render a head template that depends only on request-level information (route, locale) and maybe a fast lookup for the title.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Flush the head before slow work\",\n      \"text\": \"Flush the head before slow work\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Decide status codes before flushing\",\n      \"text\": \"Do a fast existence check (cache lookup or a primary-key query) before sending the head.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Resolve title and meta quickly or update later\",\n      \"text\": \"Use a fast lookup for the title and description, or emit a generic title and set a more specific one during rendering (search engines use the final DOM).\"\n    }\n  ]\n}\n",[838,843,844],{"type":840},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"How to Flush the Document Head Early\",\n  \"description\": \"The simplest form of streaming: send the document head with critical resource hints before the server does slow work, in any server stack.\",\n  \"datePublished\": \"2026-10-06\",\n  \"dateModified\": \"2026-10-06\",\n  \"author\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"publisher\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"mainEntityOfPage\": {\n    \"@type\": \"WebPage\",\n    \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Fnetwork-protocol-optimization\u002Fstreaming-ssr-and-early-flush\u002Fflushing-the-document-head-early\u002F\"\n  }\n}\n",[838,846,847],{"type":840},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 1,\n      \"name\": \"Home\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 2,\n      \"name\": \"Network & Server Response Optimization\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fnetwork-protocol-optimization\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 3,\n      \"name\": \"Streaming SSR & Early Flush\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fnetwork-protocol-optimization\u002Fstreaming-ssr-and-early-flush\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"Flushing the Document Head Early\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fnetwork-protocol-optimization\u002Fstreaming-ssr-and-early-flush\u002Fflushing-the-document-head-early\u002F\"\n    }\n  ]\n}\n",[849,850,851],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}",{"title":224,"searchDepth":237,"depth":237,"links":853},[854,855,856,862,863,864,865,866,867,868],{"id":139,"depth":237,"text":140},{"id":176,"depth":237,"text":177},{"id":204,"depth":237,"text":205,"children":857},[858,859,860,861],{"id":209,"depth":243,"text":210},{"id":216,"depth":243,"text":217},{"id":343,"depth":243,"text":344},{"id":350,"depth":243,"text":351},{"id":482,"depth":237,"text":483},{"id":493,"depth":237,"text":494},{"id":508,"depth":237,"text":509},{"id":654,"depth":237,"text":655},{"id":684,"depth":237,"text":685},{"id":712,"depth":237,"text":713},{"id":812,"depth":237,"text":813},"The simplest form of streaming: send the document head with critical resource hints before the server does slow work, in any server stack.","md",{"slug":872,"type":873,"breadcrumb":874,"datePublished":882,"dateModified":882},"flushing-the-document-head-early","article",[875,878,879,880],{"name":876,"url":877},"Home","\u002F",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":881},"\u002Fnetwork-protocol-optimization\u002Fstreaming-ssr-and-early-flush\u002Fflushing-the-document-head-early\u002F","2026-10-06",true,"\u002Fnetwork-protocol-optimization\u002Fstreaming-ssr-and-early-flush\u002Fflushing-the-document-head-early",{"title":886,"description":887},"Flushing the Document Head Early to Speed Up LCP","Send the HTML head with CSS, preloads and preconnects before slow server work. Framework-agnostic early flush in Node, PHP and Python, plus status code handling.","network-protocol-optimization\u002Fstreaming-ssr-and-early-flush\u002Fflushing-the-document-head-early\u002Findex","fHszqAzHoaJWgwX8ZOVNEYoQoSv1i8WOJQ55PgaImZs",[891,894],{"title":22,"path":892,"stem":893,"children":-1},"\u002Fnetwork-protocol-optimization\u002Fstreaming-ssr-and-early-flush","network-protocol-optimization\u002Fstreaming-ssr-and-early-flush\u002Findex",{"title":895,"path":896,"stem":897,"children":-1},"Streaming HTML Through CDNs and Proxies","\u002Fnetwork-protocol-optimization\u002Fstreaming-ssr-and-early-flush\u002Fstreaming-html-through-cdns-and-proxies","network-protocol-optimization\u002Fstreaming-ssr-and-early-flush\u002Fstreaming-html-through-cdns-and-proxies\u002Findex",1791308073510]