[{"data":1,"prerenderedAt":706},["ShallowReactive",2],{"content:\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fesbuild-vs-terser-for-production-minification":3,"surroundings:\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fesbuild-vs-terser-for-production-minification":697},{"id":4,"title":5,"body":6,"description":676,"extension":677,"meta":678,"navigation":690,"path":691,"seo":692,"stem":695,"__hash__":696},"content\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fesbuild-vs-terser-for-production-minification\u002Findex.md","esbuild vs Terser for production minification",{"type":7,"value":8,"toc":667},"minimark",[9,13,28,31,36,144,148,151,168,223,227,238,249,321,325,336,361,447,451,461,479,514,518,601,612,618,621,625,658,663],[10,11,5],"h1",{"id":12},"esbuild-vs-terser-for-production-minification",[14,15,16,17,22,23,27],"p",{},"This comparison extends the ",[18,19,21],"a",{"href":20},"\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002F","tree-shaking and dead code elimination"," guide and the wider ",[18,24,26],{"href":25},"\u002Fjavascript-bundle-optimization-code-splitting\u002F","JavaScript bundle optimization and code splitting"," workstream by settling a narrow but consequential choice: when you minify production JavaScript, do you use esbuild or Terser?",[14,29,30],{},"Minification is where your last few kilobytes are squeezed out before the bytes hit the wire, and it is a direct lever on the initial route JS budget (target under 150KB gzipped) and on main-thread parse time (keep individual tasks under the 50ms long-task threshold). The two dominant minifiers make opposite bets. esbuild is written in Go and minifies an order of magnitude faster than anything JavaScript-based, accepting a slightly larger output. Terser is the long-standing JavaScript minifier whose multi-pass analysis squeezes out the last percent of size at a much higher time cost. This page compares them on the four axes that matter — speed, compression ratio, mangling safety, and dead-code elimination — and tells you when each wins.",[32,33,35],"h2",{"id":34},"the-speed-versus-bytes-trade-in-one-view","The speed-versus-bytes trade in one view",[14,37,38],{},[39,40,47,48,47,52,47,56,47,66,47,73,47,80,47,85,47,91,47,96,47,100,47,103,47,107,47,110,47,113,47,117,47,120,47,123,47,127,47,130,47,133,47,136,47,140,47],"svg",{"xmlns":41,"viewBox":42,"width":43,"role":44,"ariaLabel":45,"style":46},"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","0 0 760 320","100%","img","Decision matrix comparing esbuild and Terser on minify speed, compression ratio, mangling safety, and dead-code elimination","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:#001d3d"," ",[49,50,51],"title",{},"esbuild vs Terser matrix",[53,54,55],"desc",{},"A four-row matrix scoring esbuild and Terser on the criteria that affect minified output and build time.",[57,58],"rect",{"x":59,"y":59,"width":60,"height":61,"rx":62,"fill":63,"stroke":64,"style":65},"1","758","318","10","none","currentColor","stroke-opacity:0.18",[67,68,72],"text",{"x":69,"y":70,"fill":64,"style":71},"24","38","font-size:18px;font-weight:700","Minifier decision matrix",[67,74,79],{"x":75,"y":76,"fill":77,"style":78},"430","68","#0466c8","font-size:13px;font-weight:600;text-anchor:middle","esbuild",[67,81,84],{"x":82,"y":76,"fill":83,"style":78},"640","#b8860b","Terser",[86,87],"line",{"x1":69,"y1":88,"x2":89,"y2":88,"stroke":64,"style":90},"78","736","stroke-opacity:0.3",[67,92,95],{"x":69,"y":93,"fill":64,"style":94},"112","font-size:13px","Minify speed",[67,97,99],{"x":75,"y":93,"fill":64,"style":98},"font-size:13px;text-anchor:middle","~20-100x faster",[67,101,102],{"x":82,"y":93,"fill":64,"style":98},"baseline",[67,104,106],{"x":69,"y":105,"fill":64,"style":94},"150","Compression ratio",[67,108,109],{"x":75,"y":105,"fill":64,"style":98},"within ~1-3%",[67,111,112],{"x":82,"y":105,"fill":64,"style":98},"smallest",[67,114,116],{"x":69,"y":115,"fill":64,"style":94},"188","Mangling safety",[67,118,119],{"x":75,"y":115,"fill":64,"style":98},"safe defaults",[67,121,122],{"x":82,"y":115,"fill":64,"style":98},"tunable",[67,124,126],{"x":69,"y":125,"fill":64,"style":94},"226","Dead-code elim.",[67,128,129],{"x":75,"y":125,"fill":64,"style":98},"single-pass",[67,131,132],{"x":82,"y":125,"fill":64,"style":98},"multi-pass",[86,134],{"x1":69,"y1":135,"x2":89,"y2":135,"stroke":64,"style":90},"246",[67,137,139],{"x":69,"y":138,"fill":64,"style":94},"278","esbuild trades a few percent of bytes for a huge build-time win.",[67,141,143],{"x":69,"y":142,"fill":64,"style":94},"302","Terser earns its time cost only when every byte is contested.",[32,145,147],{"id":146},"minify-speed-the-headline-difference","Minify speed: the headline difference",[14,149,150],{},"Speed is the reason esbuild exists. Because it is compiled Go with a parallel architecture, it routinely minifies a large bundle 20 to 100 times faster than Terser, which runs single-threaded in Node. On a multi-megabyte input this is the difference between a minify pass measured in tens of milliseconds versus several seconds. In a watch or preview build the gap is felt every iteration; in CI it shrinks a step that often sits on the critical path.",[14,152,153,154,158,159,162,163,167],{},"This speed is why bundlers increasingly default to esbuild for minification. Vite uses esbuild as its default minifier; webpack ships ",[155,156,157],"code",{},"TerserPlugin"," by default but lets you swap in ",[155,160,161],{},"esbuild-loader","'s minifier. The speed difference does not change a single byte your users download — it changes how fast ",[164,165,166],"em",{},"you"," ship.",[169,170,175],"pre",{"className":171,"code":172,"language":173,"meta":174,"style":174},"language-bash shiki shiki-themes github-light-high-contrast github-light-high-contrast github-light-high-contrast","# Compare minify wall-clock on the same bundle (median of 3 runs)\ntime npx esbuild app.js --minify --bundle --outfile=out.esbuild.js\ntime npx terser app.bundle.js -c -m -o out.terser.js\n# trade-off: build speed only matters if minify is on your critical path —\n# if CI caches the build, optimizing this number buys your users nothing.\n","bash","",[155,176,177,185,203,211,217],{"__ignoreMap":174},[178,179,181],"span",{"class":86,"line":180},1,[178,182,184],{"class":183},"sIIH1","# Compare minify wall-clock on the same bundle (median of 3 runs)\n",[178,186,188,192,196,199],{"class":86,"line":187},2,[178,189,191],{"class":190},"sP5qI","time",[178,193,195],{"class":194},"syybb"," npx esbuild app.js --minify --bundle --outfile",[178,197,198],{"class":190},"=",[178,200,202],{"class":201},"s-_DF","out.esbuild.js\n",[178,204,206,208],{"class":86,"line":205},3,[178,207,191],{"class":190},[178,209,210],{"class":194}," npx terser app.bundle.js -c -m -o out.terser.js\n",[178,212,214],{"class":86,"line":213},4,[178,215,216],{"class":183},"# trade-off: build speed only matters if minify is on your critical path —\n",[178,218,220],{"class":86,"line":219},5,[178,221,222],{"class":183},"# if CI caches the build, optimizing this number buys your users nothing.\n",[32,224,226],{"id":225},"compression-ratio-how-much-smaller-is-terser-really","Compression ratio: how much smaller is Terser, really",[14,228,229,230,233,234,237],{},"Terser does win on raw output size, but the margin is narrower than its reputation suggests. With multi-pass ",[155,231,232],{},"compress"," enabled, Terser typically emits output a few percent smaller than esbuild before gzip; after gzip the difference often shrinks to roughly 1-3% because the compressor recovers much of the redundancy esbuild leaves behind. On a 150KB gzipped initial route that is single-digit kilobytes — real, but small relative to what a single unnecessary dependency or a missed ",[18,235,236],{"href":20},"tree-shaking opportunity"," costs you.",[14,239,240,241,244,245,248],{},"The practical implication: chase the dependency graph before you chase the minifier. If your bundle is bloated, switching from esbuild to Terser recovers a few percent; removing a mis-shaken ",[155,242,243],{},"lodash"," or ",[155,246,247],{},"moment"," import recovers far more.",[169,250,254],{"className":251,"code":252,"language":253,"meta":174,"style":174},"language-js shiki shiki-themes github-light-high-contrast github-light-high-contrast github-light-high-contrast","\u002F\u002F terser config that maximizes ratio — and the time it costs\nmodule.exports = {\n  compress: { passes: 2 },   \u002F\u002F extra passes find more shrinking opportunities\n  mangle: { toplevel: true },\n  \u002F\u002F trade-off: passes: 2 noticeably increases minify time for ~1% extra savings;\n  \u002F\u002F skip it unless you are genuinely byte-constrained on a hot path.\n};\n","js",[155,255,256,261,279,293,304,309,315],{"__ignoreMap":174},[178,257,258],{"class":86,"line":180},[178,259,260],{"class":183},"\u002F\u002F terser config that maximizes ratio — and the time it costs\n",[178,262,263,267,270,273,276],{"class":86,"line":187},[178,264,266],{"class":265},"sf6mN","module",[178,268,269],{"class":194},".",[178,271,272],{"class":265},"exports",[178,274,275],{"class":190}," =",[178,277,278],{"class":194}," {\n",[178,280,281,284,287,290],{"class":86,"line":205},[178,282,283],{"class":194},"  compress: { passes: ",[178,285,286],{"class":265},"2",[178,288,289],{"class":194}," },   ",[178,291,292],{"class":183},"\u002F\u002F extra passes find more shrinking opportunities\n",[178,294,295,298,301],{"class":86,"line":213},[178,296,297],{"class":194},"  mangle: { toplevel: ",[178,299,300],{"class":265},"true",[178,302,303],{"class":194}," },\n",[178,305,306],{"class":86,"line":219},[178,307,308],{"class":183},"  \u002F\u002F trade-off: passes: 2 noticeably increases minify time for ~1% extra savings;\n",[178,310,312],{"class":86,"line":311},6,[178,313,314],{"class":183},"  \u002F\u002F skip it unless you are genuinely byte-constrained on a hot path.\n",[178,316,318],{"class":86,"line":317},7,[178,319,320],{"class":194},"};\n",[32,322,324],{"id":323},"mangling-safety-where-correctness-bugs-hide","Mangling safety: where correctness bugs hide",[14,326,327,328,331,332,335],{},"Mangling renames identifiers to single characters to save bytes, and this is where a minifier can silently break code. Both tools mangle local scope safely by default. The danger is ",[155,329,330],{},"mangle.properties"," (Terser) or ",[155,333,334],{},"--mangle-props"," (esbuild): renaming object properties breaks any code that accesses them by string key, reflects over them, or relies on a serialized shape (e.g. a property name sent to an API). Neither tool enables property mangling by default, and you should leave it off unless you have a reserved-name allowlist and thorough tests.",[14,337,338,339,342,343,342,346,349,350,352,353,356,357,360],{},"Terser exposes finer-grained safety knobs — ",[155,340,341],{},"keep_classnames",", ",[155,344,345],{},"keep_fnames",[155,347,348],{},"reserved"," lists, and per-option ",[155,351,232],{}," toggles — which matters when a framework or error-reporting tool depends on stable function names. esbuild offers ",[155,354,355],{},"--keep-names"," to preserve ",[155,358,359],{},"name"," properties but exposes fewer dials overall, trading configurability for a smaller correctness surface.",[169,362,364],{"className":251,"code":363,"language":253,"meta":174,"style":174},"\u002F\u002F Preserve names for code that reflects on them (DI, decorators, error stacks)\n\u002F\u002F esbuild:\n\u002F\u002F esbuild app.js --minify --keep-names\n\u002F\u002F terser:\nmodule.exports = {\n  keep_classnames: true,  \u002F\u002F some DI containers resolve by class name\n  keep_fnames: \u002FComponent$\u002F, \u002F\u002F preserve React component display names\n  \u002F\u002F trade-off: keeping names increases output size; only preserve the exact\n  \u002F\u002F patterns your runtime reflects on, not everything, or you give back the win.\n};\n",[155,365,366,371,376,381,386,398,411,430,436,442],{"__ignoreMap":174},[178,367,368],{"class":86,"line":180},[178,369,370],{"class":183},"\u002F\u002F Preserve names for code that reflects on them (DI, decorators, error stacks)\n",[178,372,373],{"class":86,"line":187},[178,374,375],{"class":183},"\u002F\u002F esbuild:\n",[178,377,378],{"class":86,"line":205},[178,379,380],{"class":183},"\u002F\u002F esbuild app.js --minify --keep-names\n",[178,382,383],{"class":86,"line":213},[178,384,385],{"class":183},"\u002F\u002F terser:\n",[178,387,388,390,392,394,396],{"class":86,"line":219},[178,389,266],{"class":265},[178,391,269],{"class":194},[178,393,272],{"class":265},[178,395,275],{"class":190},[178,397,278],{"class":194},[178,399,400,403,405,408],{"class":86,"line":311},[178,401,402],{"class":194},"  keep_classnames: ",[178,404,300],{"class":265},[178,406,407],{"class":194},",  ",[178,409,410],{"class":183},"\u002F\u002F some DI containers resolve by class name\n",[178,412,413,416,419,422,425,427],{"class":86,"line":317},[178,414,415],{"class":194},"  keep_fnames:",[178,417,418],{"class":201}," \u002FComponent",[178,420,421],{"class":190},"$",[178,423,424],{"class":201},"\u002F",[178,426,342],{"class":194},[178,428,429],{"class":183},"\u002F\u002F preserve React component display names\n",[178,431,433],{"class":86,"line":432},8,[178,434,435],{"class":183},"  \u002F\u002F trade-off: keeping names increases output size; only preserve the exact\n",[178,437,439],{"class":86,"line":438},9,[178,440,441],{"class":183},"  \u002F\u002F patterns your runtime reflects on, not everything, or you give back the win.\n",[178,443,445],{"class":86,"line":444},10,[178,446,320],{"class":194},[32,448,450],{"id":449},"dead-code-elimination-single-pass-speed-versus-multi-pass-thoroughness","Dead-code elimination: single-pass speed versus multi-pass thoroughness",[14,452,453,454,457,458,460],{},"Both minifiers perform dead-code elimination — dropping unreachable branches, unused locals, and ",[155,455,456],{},"if (false)"," blocks — but their depth differs. esbuild does competent single-pass DCE that catches the common cases. Terser's multi-pass ",[155,459,232],{}," can iterate, so eliminations that expose further eliminations get caught on a later pass, occasionally removing code esbuild leaves behind.",[14,462,463,464,467,468,471,472,474,475,269],{},"Crucially, neither minifier replaces bundler-level tree-shaking. Removing an unused ",[164,465,466],{},"export"," across module boundaries is the bundler's job (Rollup\u002Fwebpack), driven by the ",[155,469,470],{},"sideEffects"," field; the minifier only prunes within what the bundler already included. So the order of operations is: get tree-shaking right at the bundler, then let the minifier clean up the residue. If you are still seeing dead code in the output, the fix usually belongs upstream — see the dependency-graph techniques in ",[18,473,21],{"href":20}," and the bundler comparison in ",[18,476,478],{"href":477},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fdynamic-imports-and-route-based-splitting\u002Fvite-vs-webpack-bundle-splitting-performance\u002F","Vite vs webpack bundle splitting performance",[169,480,482],{"className":251,"code":481,"language":253,"meta":174,"style":174},"\u002F\u002F Define-replace lets BOTH minifiers DCE dead branches at build time\n\u002F\u002F esbuild: --define:process.env.NODE_ENV='\"production\"'\n\u002F\u002F This turns `if (process.env.NODE_ENV !== 'production')` into `if (false)`,\n\u002F\u002F which the minifier then drops entirely.\n\u002F\u002F trade-off: getting the define wrong (or forgetting it) leaves dev-only\n\u002F\u002F warning code in the production bundle, inflating bytes and parse time.\n",[155,483,484,489,494,499,504,509],{"__ignoreMap":174},[178,485,486],{"class":86,"line":180},[178,487,488],{"class":183},"\u002F\u002F Define-replace lets BOTH minifiers DCE dead branches at build time\n",[178,490,491],{"class":86,"line":187},[178,492,493],{"class":183},"\u002F\u002F esbuild: --define:process.env.NODE_ENV='\"production\"'\n",[178,495,496],{"class":86,"line":205},[178,497,498],{"class":183},"\u002F\u002F This turns `if (process.env.NODE_ENV !== 'production')` into `if (false)`,\n",[178,500,501],{"class":86,"line":213},[178,502,503],{"class":183},"\u002F\u002F which the minifier then drops entirely.\n",[178,505,506],{"class":86,"line":219},[178,507,508],{"class":183},"\u002F\u002F trade-off: getting the define wrong (or forgetting it) leaves dev-only\n",[178,510,511],{"class":86,"line":311},[178,512,513],{"class":183},"\u002F\u002F warning code in the production bundle, inflating bytes and parse time.\n",[32,515,517],{"id":516},"when-to-pick-which","When to pick which",[519,520,521,536],"table",{},[522,523,524],"thead",{},[525,526,527,532,534],"tr",{},[528,529,531],"th",{"align":530},"left","Criterion",[528,533,79],{"align":530},[528,535,84],{"align":530},[537,538,539,550,561,579,590],"tbody",{},[525,540,541,544,547],{},[542,543,95],"td",{"align":530},[542,545,546],{"align":530},"20-100x faster",[542,548,549],{"align":530},"Baseline (slowest)",[525,551,552,555,558],{},[542,553,554],{"align":530},"Output size (post-gzip)",[542,556,557],{"align":530},"Within ~1-3%",[542,559,560],{"align":530},"Smallest",[525,562,563,566,571],{},[542,564,565],{"align":530},"Mangling safety controls",[542,567,568,570],{"align":530},[155,569,355],{},", fewer dials",[542,572,573,574,424,576],{"align":530},"Granular ",[155,575,348],{},[155,577,578],{},"keep_*",[525,580,581,584,587],{},[542,582,583],{"align":530},"Dead-code elimination",[542,585,586],{"align":530},"Single-pass",[542,588,589],{"align":530},"Multi-pass",[525,591,592,595,598],{},[542,593,594],{"align":530},"Default in tooling",[542,596,597],{"align":530},"Vite default; webpack opt-in",[542,599,600],{"align":530},"webpack default",[14,602,603,607,608,269],{},[604,605,606],"strong",{},"Pick esbuild"," for almost every app. The build-speed win is enormous, the output is within a few percent of Terser after gzip, and the safe defaults reduce the chance of a mangling bug. This is the right default for new projects and for any team that values fast iteration — which in turn supports the profiling loop behind ",[18,609,611],{"href":610},"\u002Fcore-web-vitals-measurement\u002Foptimizing-first-input-delay-fid\u002F","improving First Input Delay and INP",[14,613,614,617],{},[604,615,616],{},"Pick Terser"," when you are genuinely byte-constrained on a hot path (a tiny embeddable widget, an ads-budget-sensitive script) and have measured that its multi-pass output meaningfully beats esbuild for your code, or when you need its granular name-preservation controls for a framework or error-reporting tool that reflects on identifiers. For the rare bundle where the last 1-2% is contested and tested, Terser's extra passes earn their time.",[14,619,620],{},"The meta-point: the minifier is a small lever. Spend your effort where the kilobytes actually live — dependency selection, tree-shaking hygiene, and code-split boundaries — and let a fast, safe minifier handle the final polish.",[32,622,624],{"id":623},"related","Related",[626,627,628,635,642,647,652],"ul",{},[629,630,631,634],"li",{},[18,632,633],{"href":20},"Tree-shaking and dead code elimination"," — the parent guide; minification only polishes what the bundler already pruned.",[629,636,637,641],{},[18,638,640],{"href":639},"\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Ffixing-tree-shaking-issues-with-lodash-and-moment\u002F","Fixing tree-shaking issues with lodash and moment"," — recovering far more bytes than any minifier switch.",[629,643,644,646],{},[18,645,478],{"href":477}," — how each bundler wires up its default minifier.",[629,648,649,651],{},[18,650,26],{"href":25}," — the end-to-end payload-reduction workflow.",[629,653,654,657],{},[18,655,656],{"href":610},"Optimizing First Input Delay and INP"," — why smaller minified bundles cut parse time and improve responsiveness.",[659,660,662],"script",{"type":661},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@graph\": [\n    {\n      \"@type\": \"TechArticle\",\n      \"headline\": \"esbuild vs Terser for production minification\",\n      \"description\": \"A decision matrix comparing esbuild and Terser on minification speed, compression ratio, mangling safety, and dead-code elimination, with guidance on when to pick which.\",\n      \"datePublished\": \"2026-06-18\",\n      \"dateModified\": \"2026-06-18\",\n      \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fesbuild-vs-terser-for-production-minification\u002F\"\n    },\n    {\n      \"@type\": \"HowTo\",\n      \"name\": \"Choose between esbuild and Terser for minification\",\n      \"step\": [\n        { \"@type\": \"HowToStep\", \"position\": 1, \"name\": \"Benchmark minify speed\", \"text\": \"Minify the same bundle with both tools three times and compare median wall-clock time.\" },\n        { \"@type\": \"HowToStep\", \"position\": 2, \"name\": \"Compare gzipped output\", \"text\": \"Measure the gzipped size difference; it is usually within 1-3%.\" },\n        { \"@type\": \"HowToStep\", \"position\": 3, \"name\": \"Audit mangling safety\", \"text\": \"Keep property mangling off and preserve only the names your runtime reflects on.\" },\n        { \"@type\": \"HowToStep\", \"position\": 4, \"name\": \"Verify dead-code elimination\", \"text\": \"Set NODE_ENV defines so both minifiers can drop dev-only branches.\" },\n        { \"@type\": \"HowToStep\", \"position\": 5, \"name\": \"Decide\", \"text\": \"Default to esbuild for speed; choose Terser only when bytes are contested on a hot path.\" }\n      ]\n    },\n    {\n      \"@type\": \"BreadcrumbList\",\n      \"itemListElement\": [\n        { \"@type\": \"ListItem\", \"position\": 1, \"name\": \"Home\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\" },\n        { \"@type\": \"ListItem\", \"position\": 2, \"name\": \"JavaScript Bundle Optimization & Code Splitting\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002F\" },\n        { \"@type\": \"ListItem\", \"position\": 3, \"name\": \"Tree Shaking & Dead Code Elimination\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002F\" },\n        { \"@type\": \"ListItem\", \"position\": 4, \"name\": \"esbuild vs Terser for production minification\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fesbuild-vs-terser-for-production-minification\u002F\" }\n      ]\n    }\n  ]\n}\n",[664,665,666],"style",{},"html pre.shiki code .sIIH1, html code.shiki .sIIH1{--shiki-default:#66707B;--shiki-dark:#66707B;--shiki-light:#66707B}html pre.shiki code .sP5qI, html code.shiki .sP5qI{--shiki-default:#A0111F;--shiki-dark:#A0111F;--shiki-light:#A0111F}html pre.shiki code .syybb, html code.shiki .syybb{--shiki-default:#0E1116;--shiki-dark:#0E1116;--shiki-light:#0E1116}html pre.shiki code .s-_DF, html code.shiki .s-_DF{--shiki-default:#032563;--shiki-dark:#032563;--shiki-light:#032563}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html pre.shiki code .sf6mN, html code.shiki .sf6mN{--shiki-default:#023B95;--shiki-dark:#023B95;--shiki-light:#023B95}",{"title":174,"searchDepth":187,"depth":187,"links":668},[669,670,671,672,673,674,675],{"id":34,"depth":187,"text":35},{"id":146,"depth":187,"text":147},{"id":225,"depth":187,"text":226},{"id":323,"depth":187,"text":324},{"id":449,"depth":187,"text":450},{"id":516,"depth":187,"text":517},{"id":623,"depth":187,"text":624},"A decision matrix comparing esbuild and Terser on minification speed, compression ratio, mangling safety, and dead-code elimination.","md",{"slug":12,"type":679,"breadcrumb":680,"datePublished":689,"dateModified":689},"long_tail",[681,683,685,687],{"name":682,"url":424},"Home",{"name":684,"url":25},"JavaScript Bundle Optimization & Code Splitting",{"name":686,"url":20},"Tree Shaking & Dead Code Elimination",{"name":5,"url":688},"\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fesbuild-vs-terser-for-production-minification\u002F","2026-06-18",true,"\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fesbuild-vs-terser-for-production-minification",{"title":693,"description":694},"esbuild vs Terser for Production Minification","Compare esbuild and Terser for production JS minification: speed, compression ratio, mangling safety, and dead-code elimination. A decision matrix and when to pick which.","javascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fesbuild-vs-terser-for-production-minification\u002Findex","6yqYFFihEiXALEs2Zq_9qe8zcQ9a8chqfWEqM4BeDJY",[698,702],{"title":699,"path":700,"stem":701,"children":-1},"Tree Shaking and Dead Code Elimination","\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination","javascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Findex",{"title":703,"path":704,"stem":705,"children":-1},"Fixing Tree Shaking Issues with Lodash and Moment","\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Ffixing-tree-shaking-issues-with-lodash-and-moment","javascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Ffixing-tree-shaking-issues-with-lodash-and-moment\u002Findex",1782237170600]