[{"data":1,"prerenderedAt":782},["ShallowReactive",2],{"guide-html-minification-ssr":3},{"id":4,"title":5,"body":6,"date":773,"description":774,"extension":775,"meta":776,"navigation":777,"path":778,"readingTime":128,"seo":779,"stem":780,"__hash__":781},"guides\u002Fguides\u002Fhtml-minification-ssr.md","HTML Minification in SSR Frameworks",{"type":7,"value":8,"toc":763},"minimark",[9,13,18,21,327,330,476,479,483,486,491,502,528,535,617,620,624,630,634,645,649,652,655,729,743,747,750,759],[10,11,12],"p",{},"Server-side rendering frameworks generate HTML on every request or at build time for static sites. The resulting HTML often contains unnecessary whitespace, comments, and redundant attributes that bloat page weight. HTML minification removes this overhead, but integrating it into an SSR pipeline requires understanding how each framework handles the build and delivery stages differently.",[14,15,17],"h2",{"id":16},"why-ssr-output-needs-minification","Why SSR Output Needs Minification",[10,19,20],{},"A typical server-rendered HTML document contains far more bytes than necessary for the browser to parse it correctly. Consider this Nuxt-generated snippet:",[22,23,28],"pre",{"className":24,"code":25,"language":26,"meta":27,"style":27},"language-html shiki shiki-themes github-light github-dark","\u003C!DOCTYPE html>\n\u003Chtml lang=\"en\">\n  \u003Chead>\n    \u003Cmeta charset=\"utf-8\">\n    \u003Cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    \u003C!-- Hydration marker -->\n    \u003Cmeta name=\"head:count\" content=\"3\">\n    \u003Ctitle>My App\u003C\u002Ftitle>\n  \u003C\u002Fhead>\n  \u003Cbody>\n    \u003Cdiv id=\"__nuxt\">\n      \u003Cdiv class=\"page\">\n        \u003Ch1>  Hello World  \u003C\u002Fh1>\n        \u003Cp>Some content here\u003C\u002Fp>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n    \u003Cscript type=\"module\" src=\"\u002F_nuxt\u002Fentry.js\">\u003C\u002Fscript>\n  \u003C\u002Fbody>\n\u003C\u002Fhtml>\n","html","",[29,30,31,51,71,82,101,126,133,156,171,181,191,209,227,243,257,267,277,308,317],"code",{"__ignoreMap":27},[32,33,36,40,44,48],"span",{"class":34,"line":35},"line",1,[32,37,39],{"class":38},"sVt8B","\u003C!",[32,41,43],{"class":42},"s9eBZ","DOCTYPE",[32,45,47],{"class":46},"sScJk"," html",[32,49,50],{"class":38},">\n",[32,52,54,57,59,62,65,69],{"class":34,"line":53},2,[32,55,56],{"class":38},"\u003C",[32,58,26],{"class":42},[32,60,61],{"class":46}," lang",[32,63,64],{"class":38},"=",[32,66,68],{"class":67},"sZZnC","\"en\"",[32,70,50],{"class":38},[32,72,74,77,80],{"class":34,"line":73},3,[32,75,76],{"class":38},"  \u003C",[32,78,79],{"class":42},"head",[32,81,50],{"class":38},[32,83,85,88,91,94,96,99],{"class":34,"line":84},4,[32,86,87],{"class":38},"    \u003C",[32,89,90],{"class":42},"meta",[32,92,93],{"class":46}," charset",[32,95,64],{"class":38},[32,97,98],{"class":67},"\"utf-8\"",[32,100,50],{"class":38},[32,102,104,106,108,111,113,116,119,121,124],{"class":34,"line":103},5,[32,105,87],{"class":38},[32,107,90],{"class":42},[32,109,110],{"class":46}," name",[32,112,64],{"class":38},[32,114,115],{"class":67},"\"viewport\"",[32,117,118],{"class":46}," content",[32,120,64],{"class":38},[32,122,123],{"class":67},"\"width=device-width, initial-scale=1\"",[32,125,50],{"class":38},[32,127,129],{"class":34,"line":128},6,[32,130,132],{"class":131},"sJ8bj","    \u003C!-- Hydration marker -->\n",[32,134,136,138,140,142,144,147,149,151,154],{"class":34,"line":135},7,[32,137,87],{"class":38},[32,139,90],{"class":42},[32,141,110],{"class":46},[32,143,64],{"class":38},[32,145,146],{"class":67},"\"head:count\"",[32,148,118],{"class":46},[32,150,64],{"class":38},[32,152,153],{"class":67},"\"3\"",[32,155,50],{"class":38},[32,157,159,161,164,167,169],{"class":34,"line":158},8,[32,160,87],{"class":38},[32,162,163],{"class":42},"title",[32,165,166],{"class":38},">My App\u003C\u002F",[32,168,163],{"class":42},[32,170,50],{"class":38},[32,172,174,177,179],{"class":34,"line":173},9,[32,175,176],{"class":38},"  \u003C\u002F",[32,178,79],{"class":42},[32,180,50],{"class":38},[32,182,184,186,189],{"class":34,"line":183},10,[32,185,76],{"class":38},[32,187,188],{"class":42},"body",[32,190,50],{"class":38},[32,192,194,196,199,202,204,207],{"class":34,"line":193},11,[32,195,87],{"class":38},[32,197,198],{"class":42},"div",[32,200,201],{"class":46}," id",[32,203,64],{"class":38},[32,205,206],{"class":67},"\"__nuxt\"",[32,208,50],{"class":38},[32,210,212,215,217,220,222,225],{"class":34,"line":211},12,[32,213,214],{"class":38},"      \u003C",[32,216,198],{"class":42},[32,218,219],{"class":46}," class",[32,221,64],{"class":38},[32,223,224],{"class":67},"\"page\"",[32,226,50],{"class":38},[32,228,230,233,236,239,241],{"class":34,"line":229},13,[32,231,232],{"class":38},"        \u003C",[32,234,235],{"class":42},"h1",[32,237,238],{"class":38},">  Hello World  \u003C\u002F",[32,240,235],{"class":42},[32,242,50],{"class":38},[32,244,246,248,250,253,255],{"class":34,"line":245},14,[32,247,232],{"class":38},[32,249,10],{"class":42},[32,251,252],{"class":38},">Some content here\u003C\u002F",[32,254,10],{"class":42},[32,256,50],{"class":38},[32,258,260,263,265],{"class":34,"line":259},15,[32,261,262],{"class":38},"      \u003C\u002F",[32,264,198],{"class":42},[32,266,50],{"class":38},[32,268,270,273,275],{"class":34,"line":269},16,[32,271,272],{"class":38},"    \u003C\u002F",[32,274,198],{"class":42},[32,276,50],{"class":38},[32,278,280,282,285,288,290,293,296,298,301,304,306],{"class":34,"line":279},17,[32,281,87],{"class":38},[32,283,284],{"class":42},"script",[32,286,287],{"class":46}," type",[32,289,64],{"class":38},[32,291,292],{"class":67},"\"module\"",[32,294,295],{"class":46}," src",[32,297,64],{"class":38},[32,299,300],{"class":67},"\"\u002F_nuxt\u002Fentry.js\"",[32,302,303],{"class":38},">\u003C\u002F",[32,305,284],{"class":42},[32,307,50],{"class":38},[32,309,311,313,315],{"class":34,"line":310},18,[32,312,176],{"class":38},[32,314,188],{"class":42},[32,316,50],{"class":38},[32,318,320,323,325],{"class":34,"line":319},19,[32,321,322],{"class":38},"\u003C\u002F",[32,324,26],{"class":42},[32,326,50],{"class":38},[10,328,329],{},"After minification, the same document shrinks considerably:",[22,331,333],{"className":24,"code":332,"language":26,"meta":27,"style":27},"\u003C!DOCTYPE html>\u003Chtml lang=\"en\">\u003Chead>\u003Cmeta charset=\"utf-8\">\u003Cmeta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\u003Ctitle>My App\u003C\u002Ftitle>\u003C\u002Fhead>\u003Cbody>\u003Cdiv id=\"__nuxt\">\u003Cdiv class=\"page\">\u003Ch1>Hello World\u003C\u002Fh1>\u003Cp>Some content here\u003C\u002Fp>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cscript type=\"module\" src=\"\u002F_nuxt\u002Fentry.js\">\u003C\u002Fscript>\u003C\u002Fbody>\u003C\u002Fhtml>\n",[29,334,335],{"__ignoreMap":27},[32,336,337,339,341,343,346,348,350,352,354,356,358,360,362,364,366,368,370,372,374,376,378,380,382,385,387,389,391,393,395,397,399,401,403,405,407,409,411,413,415,417,419,421,423,425,428,430,432,434,436,438,440,442,444,446,448,450,452,454,456,458,460,462,464,466,468,470,472,474],{"class":34,"line":35},[32,338,39],{"class":38},[32,340,43],{"class":42},[32,342,47],{"class":46},[32,344,345],{"class":38},">\u003C",[32,347,26],{"class":42},[32,349,61],{"class":46},[32,351,64],{"class":38},[32,353,68],{"class":67},[32,355,345],{"class":38},[32,357,79],{"class":42},[32,359,345],{"class":38},[32,361,90],{"class":42},[32,363,93],{"class":46},[32,365,64],{"class":38},[32,367,98],{"class":67},[32,369,345],{"class":38},[32,371,90],{"class":42},[32,373,110],{"class":46},[32,375,64],{"class":38},[32,377,115],{"class":67},[32,379,118],{"class":46},[32,381,64],{"class":38},[32,383,384],{"class":67},"\"width=device-width,initial-scale=1\"",[32,386,345],{"class":38},[32,388,163],{"class":42},[32,390,166],{"class":38},[32,392,163],{"class":42},[32,394,303],{"class":38},[32,396,79],{"class":42},[32,398,345],{"class":38},[32,400,188],{"class":42},[32,402,345],{"class":38},[32,404,198],{"class":42},[32,406,201],{"class":46},[32,408,64],{"class":38},[32,410,206],{"class":67},[32,412,345],{"class":38},[32,414,198],{"class":42},[32,416,219],{"class":46},[32,418,64],{"class":38},[32,420,224],{"class":67},[32,422,345],{"class":38},[32,424,235],{"class":42},[32,426,427],{"class":38},">Hello World\u003C\u002F",[32,429,235],{"class":42},[32,431,345],{"class":38},[32,433,10],{"class":42},[32,435,252],{"class":38},[32,437,10],{"class":42},[32,439,303],{"class":38},[32,441,198],{"class":42},[32,443,303],{"class":38},[32,445,198],{"class":42},[32,447,345],{"class":38},[32,449,284],{"class":42},[32,451,287],{"class":46},[32,453,64],{"class":38},[32,455,292],{"class":67},[32,457,295],{"class":46},[32,459,64],{"class":38},[32,461,300],{"class":67},[32,463,303],{"class":38},[32,465,284],{"class":42},[32,467,303],{"class":38},[32,469,188],{"class":42},[32,471,303],{"class":38},[32,473,26],{"class":42},[32,475,50],{"class":38},[10,477,478],{},"The savings range from 15-30% depending on the amount of whitespace and comments in the original output. For high-traffic sites, this reduction translates to meaningful bandwidth savings and faster Time to First Byte (TTFB), especially on mobile networks.",[14,480,482],{"id":481},"framework-specific-minification","Framework-Specific Minification",[10,484,485],{},"Each major SSR framework handles HTML minification differently, and the approachdepends on whether the output is generated at build time (SSG) or request time (SSR).",[487,488,490],"h3",{"id":489},"nuxt","Nuxt",[10,492,493,494,497,498,501],{},"Nuxt uses Vite (or Webpack) for builds. For static generation (",[29,495,496],{},"nuxt generate","), the HTML output passes through Vite's built-in HTML minification, which is powered by ",[29,499,500],{},"html-minifier-terser",". In production mode, Vite automatically minifies HTML with sensible defaults:",[503,504,505,509,512,515,522],"ul",{},[506,507,508],"li",{},"Removes comments",[506,510,511],{},"Collapses whitespace",[506,513,514],{},"Removes optional tags",[506,516,517,518,521],{},"Minifies CSS inside ",[29,519,520],{},"\u003Cstyle>"," tags",[506,523,524,525,521],{},"Minifies JS inside ",[29,526,527],{},"\u003Cscript>",[10,529,530,531,534],{},"For dynamic SSR (",[29,532,533],{},"nuxt build"," + server), the Nitro server renders HTML on each request. By default, Nitro does not minify this output because minification adds latency to every response. To enable it, configure Nitro's HTML transformation:",[22,536,540],{"className":537,"code":538,"language":539,"meta":27,"style":27},"language-typescript shiki shiki-themes github-light github-dark","\u002F\u002F nuxt.config.ts\nexport default defineNuxtConfig({\n  nitro: {\n    compressHTML: {\n      minify: true,\n      collapseWhitespace: true,\n      removeComments: true,\n    },\n  },\n})\n","typescript",[29,541,542,547,562,567,572,584,593,602,607,612],{"__ignoreMap":27},[32,543,544],{"class":34,"line":35},[32,545,546],{"class":131},"\u002F\u002F nuxt.config.ts\n",[32,548,549,553,556,559],{"class":34,"line":53},[32,550,552],{"class":551},"szBVR","export",[32,554,555],{"class":551}," default",[32,557,558],{"class":46}," defineNuxtConfig",[32,560,561],{"class":38},"({\n",[32,563,564],{"class":34,"line":73},[32,565,566],{"class":38},"  nitro: {\n",[32,568,569],{"class":34,"line":84},[32,570,571],{"class":38},"    compressHTML: {\n",[32,573,574,577,581],{"class":34,"line":103},[32,575,576],{"class":38},"      minify: ",[32,578,580],{"class":579},"sj4cs","true",[32,582,583],{"class":38},",\n",[32,585,586,589,591],{"class":34,"line":128},[32,587,588],{"class":38},"      collapseWhitespace: ",[32,590,580],{"class":579},[32,592,583],{"class":38},[32,594,595,598,600],{"class":34,"line":135},[32,596,597],{"class":38},"      removeComments: ",[32,599,580],{"class":579},[32,601,583],{"class":38},[32,603,604],{"class":34,"line":158},[32,605,606],{"class":38},"    },\n",[32,608,609],{"class":34,"line":173},[32,610,611],{"class":38},"  },\n",[32,613,614],{"class":34,"line":183},[32,615,616],{"class":38},"})\n",[10,618,619],{},"The performance trade-off is real: minifying HTML on every request adds roughly 1-3ms per page on a typical server. For most applications, this is negligible, but high-throughput APIs serving thousands of requests per second should benchmark the impact.",[487,621,623],{"id":622},"nextjs","Next.js",[10,625,626,627,629],{},"Next.js uses ",[29,628,500],{}," for static pages generated at build time. For server-rendered pages, Next.js does not minify HTML by default. You can add a custom server middleware to minify responses, but the Next.js team recommends handling this at the CDN or reverse proxy level instead.",[487,631,633],{"id":632},"sveltekit","SvelteKit",[10,635,636,637,640,641,644],{},"SvelteKit's adapter-static generates pre-rendered HTML that Vite minifies automatically. For the adapter-node server, SvelteKit includes a ",[29,638,639],{},"polyfill:"," option but does not provide built-in HTML minification for dynamic responses. The recommended approach is to use a reverse proxy like Nginx with the ",[29,642,643],{},"sub_filter"," module or a CDN with on-the-fly minification.",[14,646,648],{"id":647},"minification-and-hydration","Minification and Hydration",[10,650,651],{},"SSR frameworks inject hydration markers and inline data into the HTML to enable client-side interactivity. Minification must preserve these artifacts, or hydration fails silently or produces mismatches.",[10,653,654],{},"Key artifacts to preserve:",[656,657,658,674],"table",{},[659,660,661],"thead",{},[662,663,664,668,671],"tr",{},[665,666,667],"th",{},"Framework",[665,669,670],{},"Artifact",[665,672,673],{},"Purpose",[675,676,677,691,704,717],"tbody",{},[662,678,679,682,688],{},[680,681,490],"td",{},[680,683,684,687],{},[29,685,686],{},"__nuxt"," div",[680,689,690],{},"Mount point for Vue app",[662,692,693,695,701],{},[680,694,490],{},[680,696,697,700],{},[29,698,699],{},"data-ssr"," attributes",[680,702,703],{},"Hydration state tracking",[662,705,706,708,714],{},[680,707,623],{},[680,709,710,713],{},[29,711,712],{},"__NEXT_DATA__"," script",[680,715,716],{},"Serialized page props",[662,718,719,721,726],{},[680,720,633],{},[680,722,723,700],{},[29,724,725],{},"sveltekit:data",[680,727,728],{},"Hydration data",[10,730,731,732,735,736,738,739,742],{},"Most minifiers handle these correctly by default because they preserve ",[29,733,734],{},"data-*"," attributes and ",[29,737,527],{}," tag content. However, if you configure aggressive options like ",[29,740,741],{},"removeAttributeQuotes",", you may break attribute-based hydration markers that expect exact quoting.",[14,744,746],{"id":745},"recommendations","Recommendations",[10,748,749],{},"For statically generated sites, rely on your framework's built-in build-time minification—no additional configuration needed. For dynamic SSR, enable server-side minification only if you have measured the latency impact. The simplest and most performant approach for dynamic SSR is to delegate HTML minification to your CDN, which can minify at the edge without adding origin server latency.",[10,751,752,753,758],{},"To minify HTML snippets or verify minification output, the ",[754,755,757],"a",{"href":756},"\u002Ftools\u002Fhtml-minifier","HTML Minifier tool"," provides instant results with configurable options.",[760,761,762],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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 pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":27,"searchDepth":53,"depth":53,"links":764},[765,766,771,772],{"id":16,"depth":53,"text":17},{"id":481,"depth":53,"text":482,"children":767},[768,769,770],{"id":489,"depth":73,"text":490},{"id":622,"depth":73,"text":623},{"id":632,"depth":73,"text":633},{"id":647,"depth":53,"text":648},{"id":745,"depth":53,"text":746},"2026-05-28","How Nuxt, Next.js, and SvelteKit handle HTML minification in production builds.","md",{},true,"\u002Fguides\u002Fhtml-minification-ssr",{"title":5,"description":774},"guides\u002Fhtml-minification-ssr","XII-14M-Yv6gwTuZP0CSpbu-x1h0VIrg3ZZ8Y97km4c",1780401334456]