[{"data":1,"prerenderedAt":2973},["ShallowReactive",2],{"blog:\u002Fblog\u002Fbun-nuxt4-runtime-guide":3},{"page":4,"surround":1947},{"id":5,"title":6,"author":7,"body":8,"brandColor":1930,"colorBg":1930,"colorBgSecondary":1930,"colorBrand":1930,"colorFooter":1930,"colorFooterText":1930,"colorHeaders":1930,"colorInvertedText":1930,"colorText":1930,"colorTopbar":1930,"coverImage":1930,"date":1931,"description":1932,"draft":1933,"extension":1934,"galleryDark":1933,"galleryImage":1930,"gallerySize":1930,"h1":15,"hoverVideo":1930,"label":1935,"meta":1936,"navigation":182,"order":134,"path":1937,"seo":1938,"stem":1939,"tags":1940,"theme":1945,"__hash__":1946},"blog\u002Fblog\u002Fbun-nuxt4-runtime-guide.mdc","Bun Runtime with Nuxt 4: What Works, What Breaks, What to Do - Ben Nasedkin","Ben Nasedkin",{"type":9,"value":10,"toc":1876},"minimark",[11,16,20,25,28,57,61,64,67,72,83,86,89,95,99,103,106,150,154,157,202,209,213,220,283,286,309,313,324,328,332,338,341,345,352,358,361,436,440,443,446,450,456,462,466,477,480,491,495,501,504,559,563,569,573,678,682,685,699,705,709,765,769,772,776,783,789,792,801,814,818,823,843,849,854,857,906,911,914,937,941,944,1026,1030,1033,1092,1096,1103,1130,1134,1138,1198,1202,1205,1208,1211,1215,1219,1233,1237,1251,1255,1259,1267,1295,1312,1316,1429,1433,1473,1482,1486,1490,1576,1580,1603,1607,1610,1684,1687,1691,1694,1720,1723,1727,1746,1763,1780,1797,1813,1827,1843,1857,1872],[12,13,15],"h1",{"id":14},"bun-runtime-with-nuxt-4","Bun Runtime with Nuxt 4",[17,18,19],"p",{},"Bun promises faster installs, native TypeScript, and better performance. Nuxt 4 supports it. But the reality is more nuanced.",[21,22,24],"h2",{"id":23},"the-promise","The Promise",[17,26,27],{},"Bun offers significant improvements over Node.js:",[29,30,31,39,45,51],"ol",{},[32,33,34,38],"li",{},[35,36,37],"strong",{},"4x faster package installs"," — Native resolver, no intermediate steps",[32,40,41,44],{},[35,42,43],{},"Native TypeScript"," — No transpilation required",[32,46,47,50],{},[35,48,49],{},"Faster HTTP"," — Up to 2.8x more requests per second",[32,52,53,56],{},[35,54,55],{},"Single binary"," — Runtime, bundler, package manager in one",[21,58,60],{"id":59},"current-status","Current Status",[17,62,63],{},"Nuxt officially supports Bun since version 3.6. Nuxt 4 continues this support through Nitro's Bun preset.",[17,65,66],{},"The catch: support does not mean parity. Several edge cases break.",[68,69,71],"h3",{"id":70},"recommended-versions","Recommended Versions",[73,74,79],"pre",{"className":75,"code":77,"language":78},[76],"language-text","bun@1.3.6 with nuxt@4.2.2\n","text",[80,81,77],"code",{"__ignoreMap":82},"",[17,84,85],{},"Latest stable as of January 2026. Bun joined Anthropic in December 2025 — expect tighter integration with AI tooling.",[17,87,88],{},"Avoid Bun 1.2.14 through 1.2.20. Socket connection errors plague these versions with Nuxt.",[17,90,91,94],{},[35,92,93],{},"Note:"," Nuxt 3 reaches end of maintenance at the end of January 2026. Migrate to Nuxt 4 if you haven't already.",[21,96,98],{"id":97},"configuration","Configuration",[68,100,102],{"id":101},"basic-setup","Basic Setup",[17,104,105],{},"Initialize a new project:",[73,107,111],{"className":108,"code":109,"language":110,"meta":82,"style":82},"language-bash shiki shiki-themes github-light github-dark","bunx nuxi init my-app\ncd my-app\nbun install\n","bash",[80,112,113,132,141],{"__ignoreMap":82},[114,115,118,122,126,129],"span",{"class":116,"line":117},"line",1,[114,119,121],{"class":120},"sScJk","bunx",[114,123,125],{"class":124},"sZZnC"," nuxi",[114,127,128],{"class":124}," init",[114,130,131],{"class":124}," my-app\n",[114,133,135,139],{"class":116,"line":134},2,[114,136,138],{"class":137},"sj4cs","cd",[114,140,131],{"class":124},[114,142,144,147],{"class":116,"line":143},3,[114,145,146],{"class":120},"bun",[114,148,149],{"class":124}," install\n",[68,151,153],{"id":152},"development","Development",[17,155,156],{},"Two modes exist:",[73,158,160],{"className":108,"code":159,"language":110,"meta":82,"style":82},"# Uses Node.js runtime (default)\nbun run dev\n\n# Uses Bun runtime\nbun --bun run dev\n",[80,161,162,168,178,184,190],{"__ignoreMap":82},[114,163,164],{"class":116,"line":117},[114,165,167],{"class":166},"sJ8bj","# Uses Node.js runtime (default)\n",[114,169,170,172,175],{"class":116,"line":134},[114,171,146],{"class":120},[114,173,174],{"class":124}," run",[114,176,177],{"class":124}," dev\n",[114,179,180],{"class":116,"line":143},[114,181,183],{"emptyLinePlaceholder":182},true,"\n",[114,185,187],{"class":116,"line":186},4,[114,188,189],{"class":166},"# Uses Bun runtime\n",[114,191,193,195,198,200],{"class":116,"line":192},5,[114,194,146],{"class":120},[114,196,197],{"class":137}," --bun",[114,199,174],{"class":124},[114,201,177],{"class":124},[17,203,204,205,208],{},"The ",[80,206,207],{},"--bun"," flag forces the Bun runtime. Without it, the Nuxt CLI falls back to Node.js.",[68,210,212],{"id":211},"production-build","Production Build",[17,214,215,216,219],{},"Configure the Nitro preset in ",[80,217,218],{},"nuxt.config.ts",":",[73,221,225],{"className":222,"code":223,"language":224,"meta":82,"style":82},"language-typescript shiki shiki-themes github-light github-dark","export default defineNuxtConfig({\n  compatibilityDate: '2025-01-14',\n\n  nitro: {\n    preset: 'bun'\n  }\n})\n","typescript",[80,226,227,243,254,258,263,271,277],{"__ignoreMap":82},[114,228,229,233,236,239],{"class":116,"line":117},[114,230,232],{"class":231},"szBVR","export",[114,234,235],{"class":231}," default",[114,237,238],{"class":120}," defineNuxtConfig",[114,240,242],{"class":241},"sVt8B","({\n",[114,244,245,248,251],{"class":116,"line":134},[114,246,247],{"class":241},"  compatibilityDate: ",[114,249,250],{"class":124},"'2025-01-14'",[114,252,253],{"class":241},",\n",[114,255,256],{"class":116,"line":143},[114,257,183],{"emptyLinePlaceholder":182},[114,259,260],{"class":116,"line":186},[114,261,262],{"class":241},"  nitro: {\n",[114,264,265,268],{"class":116,"line":192},[114,266,267],{"class":241},"    preset: ",[114,269,270],{"class":124},"'bun'\n",[114,272,274],{"class":116,"line":273},6,[114,275,276],{"class":241},"  }\n",[114,278,280],{"class":116,"line":279},7,[114,281,282],{"class":241},"})\n",[17,284,285],{},"Or set via environment variable:",[73,287,289],{"className":108,"code":288,"language":110,"meta":82,"style":82},"NITRO_PRESET=bun bun run build\n",[80,290,291],{"__ignoreMap":82},[114,292,293,296,299,301,304,306],{"class":116,"line":117},[114,294,295],{"class":241},"NITRO_PRESET",[114,297,298],{"class":231},"=",[114,300,146],{"class":124},[114,302,303],{"class":120}," bun",[114,305,174],{"class":124},[114,307,308],{"class":124}," build\n",[68,310,312],{"id":311},"why-the-preset-matters","Why the Preset Matters",[17,314,315,316,319,320,323],{},"The default ",[80,317,318],{},"node-server"," preset does not bundle Bun-specific exports. If your app uses packages with Bun-specific features (like ",[80,321,322],{},"bun:sqlite","), production builds break without the Bun preset.",[21,325,327],{"id":326},"known-issues","Known Issues",[68,329,331],{"id":330},"socket-errors-on-windows","Socket Errors on Windows",[73,333,336],{"className":334,"code":335,"language":78},[76],"ENOENT: no such file or directory, listen '\\\\.\\pipe\\nuxt-dev-XXXX.sock'\n",[80,337,335],{"__ignoreMap":82},[17,339,340],{},"Bun 1.2.14–1.2.20 fails on Windows with Nuxt 4. The workaround: use WSL.",[68,342,344],{"id":343},"hmr-breaks-with-bun-runtime","HMR Breaks with Bun Runtime",[17,346,347,348,351],{},"When using ",[80,349,350],{},"bun --bun run dev",", WebSocket connections fail:",[73,353,356],{"className":354,"code":355,"language":78},[76],"WebSocket connection to 'ws:\u002F\u002Flocalhost:24678\u002F_nuxt\u002F' failed\n[vite] server connection lost\n",[80,357,355],{"__ignoreMap":82},[17,359,360],{},"Fix by enabling polling:",[73,362,364],{"className":222,"code":363,"language":224,"meta":82,"style":82},"\u002F\u002F nuxt.config.ts\nexport default defineNuxtConfig({\n  vite: {\n    server: {\n      watch: {\n        usePolling: true,\n        interval: 100\n      }\n    }\n  }\n})\n",[80,365,366,371,381,386,391,396,406,414,420,426,431],{"__ignoreMap":82},[114,367,368],{"class":116,"line":117},[114,369,370],{"class":166},"\u002F\u002F nuxt.config.ts\n",[114,372,373,375,377,379],{"class":116,"line":134},[114,374,232],{"class":231},[114,376,235],{"class":231},[114,378,238],{"class":120},[114,380,242],{"class":241},[114,382,383],{"class":116,"line":143},[114,384,385],{"class":241},"  vite: {\n",[114,387,388],{"class":116,"line":186},[114,389,390],{"class":241},"    server: {\n",[114,392,393],{"class":116,"line":192},[114,394,395],{"class":241},"      watch: {\n",[114,397,398,401,404],{"class":116,"line":273},[114,399,400],{"class":241},"        usePolling: ",[114,402,403],{"class":137},"true",[114,405,253],{"class":241},[114,407,408,411],{"class":116,"line":279},[114,409,410],{"class":241},"        interval: ",[114,412,413],{"class":137},"100\n",[114,415,417],{"class":116,"line":416},8,[114,418,419],{"class":241},"      }\n",[114,421,423],{"class":116,"line":422},9,[114,424,425],{"class":241},"    }\n",[114,427,429],{"class":116,"line":428},10,[114,430,276],{"class":241},[114,432,434],{"class":116,"line":433},11,[114,435,282],{"class":241},[68,437,439],{"id":438},"_400-errors-on-non-get-requests","400 Errors on Non-GET Requests",[17,441,442],{},"All POST, PUT, DELETE requests return 400 in dev mode when using the Bun runtime or preset.",[17,444,445],{},"This only affects development. Production builds work correctly.",[68,447,449],{"id":448},"fsevents-crashes-on-macos","fsevents Crashes on macOS",[73,451,454],{"className":452,"code":453,"language":78},[76],"Assertion failed: function fse_dispatch_event, file fsevents.c, line 151\n",[80,455,453],{"__ignoreMap":82},[17,457,458,459,461],{},"Affects macOS with Nuxt 3.16.0+ and Bun 1.2.4+. Workaround: run without the ",[80,460,207],{}," flag.",[68,463,465],{"id":464},"memory-leak-in-dev-mode","Memory Leak in Dev Mode",[17,467,468,469,472,473,476],{},"When running ",[80,470,471],{},"nuxt dev"," with ",[80,474,475],{},"compatibilityVersion: 4",", memory usage climbs steadily. Starts at ~500MB, reaches 6GB after 5 minutes.",[17,478,479],{},"Only affects Bun runtime in development. Production builds and Node.js runtime work fine.",[17,481,482,483,490],{},"Tracked in ",[484,485,489],"a",{"href":486,"rel":487},"https:\u002F\u002Fgithub.com\u002Foven-sh\u002Fbun\u002Fissues\u002F16219",[488],"nofollow","GitHub Issue #16219",".",[68,492,494],{"id":493},"crossws-module-error","crossws Module Error",[73,496,499],{"className":497,"code":498,"language":78},[76],"RollupError: This module cannot be imported in server runtime.\n[importing crossws\u002Fdist\u002Fadapters\u002Fbun.mjs]\n",[80,500,498],{"__ignoreMap":82},[17,502,503],{},"Add to your config:",[73,505,507],{"className":222,"code":506,"language":224,"meta":82,"style":82},"export default defineNuxtConfig({\n  nitro: {\n    preset: 'bun',\n    rollupConfig: {\n      external: ['bun']\n    }\n  }\n})\n",[80,508,509,519,523,532,537,547,551,555],{"__ignoreMap":82},[114,510,511,513,515,517],{"class":116,"line":117},[114,512,232],{"class":231},[114,514,235],{"class":231},[114,516,238],{"class":120},[114,518,242],{"class":241},[114,520,521],{"class":116,"line":134},[114,522,262],{"class":241},[114,524,525,527,530],{"class":116,"line":143},[114,526,267],{"class":241},[114,528,529],{"class":124},"'bun'",[114,531,253],{"class":241},[114,533,534],{"class":116,"line":186},[114,535,536],{"class":241},"    rollupConfig: {\n",[114,538,539,542,544],{"class":116,"line":192},[114,540,541],{"class":241},"      external: [",[114,543,529],{"class":124},[114,545,546],{"class":241},"]\n",[114,548,549],{"class":116,"line":273},[114,550,425],{"class":241},[114,552,553],{"class":116,"line":279},[114,554,276],{"class":241},[114,556,557],{"class":116,"line":416},[114,558,282],{"class":241},[21,560,562],{"id":561},"bun-sqlite","Bun SQLite",[17,564,565,566,568],{},"Bun ships with a native SQLite driver via ",[80,567,322],{},". Zero dependencies, fast, and built-in.",[68,570,572],{"id":571},"using-bunsqlite-in-server-routes","Using bun:sqlite in Server Routes",[73,574,576],{"className":222,"code":575,"language":224,"meta":82,"style":82},"\u002F\u002F server\u002Fapi\u002Fusers.get.ts\nimport { Database } from 'bun:sqlite'\n\nconst db = new Database('mydb.sqlite')\n\nexport default defineEventHandler(() => {\n  return db.query('SELECT * FROM users').all()\n})\n",[80,577,578,583,597,601,627,631,649,674],{"__ignoreMap":82},[114,579,580],{"class":116,"line":117},[114,581,582],{"class":166},"\u002F\u002F server\u002Fapi\u002Fusers.get.ts\n",[114,584,585,588,591,594],{"class":116,"line":134},[114,586,587],{"class":231},"import",[114,589,590],{"class":241}," { Database } ",[114,592,593],{"class":231},"from",[114,595,596],{"class":124}," 'bun:sqlite'\n",[114,598,599],{"class":116,"line":143},[114,600,183],{"emptyLinePlaceholder":182},[114,602,603,606,609,612,615,618,621,624],{"class":116,"line":186},[114,604,605],{"class":231},"const",[114,607,608],{"class":137}," db",[114,610,611],{"class":231}," =",[114,613,614],{"class":231}," new",[114,616,617],{"class":120}," Database",[114,619,620],{"class":241},"(",[114,622,623],{"class":124},"'mydb.sqlite'",[114,625,626],{"class":241},")\n",[114,628,629],{"class":116,"line":192},[114,630,183],{"emptyLinePlaceholder":182},[114,632,633,635,637,640,643,646],{"class":116,"line":273},[114,634,232],{"class":231},[114,636,235],{"class":231},[114,638,639],{"class":120}," defineEventHandler",[114,641,642],{"class":241},"(() ",[114,644,645],{"class":231},"=>",[114,647,648],{"class":241}," {\n",[114,650,651,654,657,660,662,665,668,671],{"class":116,"line":279},[114,652,653],{"class":231},"  return",[114,655,656],{"class":241}," db.",[114,658,659],{"class":120},"query",[114,661,620],{"class":241},[114,663,664],{"class":124},"'SELECT * FROM users'",[114,666,667],{"class":241},").",[114,669,670],{"class":120},"all",[114,672,673],{"class":241},"()\n",[114,675,676],{"class":116,"line":416},[114,677,282],{"class":241},[68,679,681],{"id":680},"the-catch","The Catch",[17,683,684],{},"This only works when:",[29,686,687,693],{},[32,688,689,690,692],{},"Running with Bun runtime (",[80,691,350],{}," or production with Bun preset)",[32,694,695,696],{},"Building with ",[80,697,698],{},"nitro.preset: 'bun'",[17,700,701,702,704],{},"Without the Bun preset, production builds use Node.js and ",[80,703,322],{}," imports fail.",[68,706,708],{"id":707},"configuration-for-bunsqlite","Configuration for bun:sqlite",[73,710,712],{"className":222,"code":711,"language":224,"meta":82,"style":82},"\u002F\u002F nuxt.config.ts\nexport default defineNuxtConfig({\n  nitro: {\n    preset: 'bun',\n    rollupConfig: {\n      external: ['bun:sqlite']\n    }\n  }\n})\n",[80,713,714,718,728,732,740,744,753,757,761],{"__ignoreMap":82},[114,715,716],{"class":116,"line":117},[114,717,370],{"class":166},[114,719,720,722,724,726],{"class":116,"line":134},[114,721,232],{"class":231},[114,723,235],{"class":231},[114,725,238],{"class":120},[114,727,242],{"class":241},[114,729,730],{"class":116,"line":143},[114,731,262],{"class":241},[114,733,734,736,738],{"class":116,"line":186},[114,735,267],{"class":241},[114,737,529],{"class":124},[114,739,253],{"class":241},[114,741,742],{"class":116,"line":192},[114,743,536],{"class":241},[114,745,746,748,751],{"class":116,"line":273},[114,747,541],{"class":241},[114,749,750],{"class":124},"'bun:sqlite'",[114,752,546],{"class":241},[114,754,755],{"class":116,"line":279},[114,756,425],{"class":241},[114,758,759],{"class":116,"line":416},[114,760,276],{"class":241},[114,762,763],{"class":116,"line":422},[114,764,282],{"class":241},[21,766,768],{"id":767},"nuxt-content-and-sqlite","Nuxt Content and SQLite",[17,770,771],{},"Nuxt Content v3 uses SQLite internally. This creates friction with Bun.",[68,773,775],{"id":774},"the-problem","The Problem",[17,777,778,779,782],{},"Nuxt Content depends on ",[80,780,781],{},"better-sqlite3"," for Node.js. This native module doesn't compile for Bun — different ABI versions.",[73,784,787],{"className":785,"code":786,"language":78},[76],"Error: The module 'better_sqlite3' was compiled against a different Node.js ABI version\n",[80,788,786],{"__ignoreMap":82},[68,790,60],{"id":791},"current-status-1",[17,793,794,795,797,798,800],{},"Nuxt Content should auto-detect Bun and use ",[80,796,322],{}," instead of ",[80,799,781],{},". In practice, detection fails in some scenarios.",[17,802,482,803,808,809,490],{},[484,804,807],{"href":805,"rel":806},"https:\u002F\u002Fgithub.com\u002Fnuxt\u002Fcontent\u002Fissues\u002F2936",[488],"GitHub Issue #2936"," and ",[484,810,813],{"href":811,"rel":812},"https:\u002F\u002Fgithub.com\u002Fnuxt\u002Fcontent\u002Fissues\u002F3118",[488],"Issue #3118",[68,815,817],{"id":816},"workarounds","Workarounds",[17,819,820],{},[35,821,822],{},"Option 1: Install with npm, run with Bun",[73,824,826],{"className":108,"code":825,"language":110,"meta":82,"style":82},"npm install\nbun run dev\n",[80,827,828,835],{"__ignoreMap":82},[114,829,830,833],{"class":116,"line":117},[114,831,832],{"class":120},"npm",[114,834,149],{"class":124},[114,836,837,839,841],{"class":116,"line":134},[114,838,146],{"class":120},[114,840,174],{"class":124},[114,842,177],{"class":124},[17,844,845,846,848],{},"This bypasses the ",[80,847,781],{}," compilation issue during install.",[17,850,851],{},[35,852,853],{},"Option 2: Use Node.js native SQLite (v22.5+)",[17,855,856],{},"If you're on Node.js 22.5+, enable experimental native SQLite:",[73,858,860],{"className":222,"code":859,"language":224,"meta":82,"style":82},"\u002F\u002F nuxt.config.ts\nexport default defineNuxtConfig({\n  content: {\n    experimental: {\n      nativeSqlite: true\n    }\n  }\n})\n",[80,861,862,866,876,881,886,894,898,902],{"__ignoreMap":82},[114,863,864],{"class":116,"line":117},[114,865,370],{"class":166},[114,867,868,870,872,874],{"class":116,"line":134},[114,869,232],{"class":231},[114,871,235],{"class":231},[114,873,238],{"class":120},[114,875,242],{"class":241},[114,877,878],{"class":116,"line":143},[114,879,880],{"class":241},"  content: {\n",[114,882,883],{"class":116,"line":186},[114,884,885],{"class":241},"    experimental: {\n",[114,887,888,891],{"class":116,"line":192},[114,889,890],{"class":241},"      nativeSqlite: ",[114,892,893],{"class":137},"true\n",[114,895,896],{"class":116,"line":273},[114,897,425],{"class":241},[114,899,900],{"class":116,"line":279},[114,901,276],{"class":241},[114,903,904],{"class":116,"line":416},[114,905,282],{"class":241},[17,907,908],{},[35,909,910],{},"Option 3: Skip Nuxt Content for Bun projects",[17,912,913],{},"If you need full Bun runtime in production, consider alternatives:",[915,916,917,924,934],"ul",{},[32,918,919,920,923],{},"Static markdown with ",[80,921,922],{},"@nuxt\u002Fcontent"," in prerender mode",[32,925,926,927,930,931],{},"Custom markdown parsing with ",[80,928,929],{},"marked"," or ",[80,932,933],{},"remark",[32,935,936],{},"External CMS (Strapi, Sanity, Contentful)",[68,938,940],{"id":939},"production-builds","Production Builds",[17,942,943],{},"Nuxt Content works in production builds if you prerender content at build time. The SQLite database gets bundled into the output.",[73,945,947],{"className":222,"code":946,"language":224,"meta":82,"style":82},"\u002F\u002F nuxt.config.ts\nexport default defineNuxtConfig({\n  content: {\n    database: {\n      type: 'sqlite',\n      filename: ':memory:'\n    }\n  },\n  routeRules: {\n    '\u002Fblog\u002F**': { prerender: true }\n  }\n})\n",[80,948,949,953,963,967,972,982,990,994,999,1004,1017,1021],{"__ignoreMap":82},[114,950,951],{"class":116,"line":117},[114,952,370],{"class":166},[114,954,955,957,959,961],{"class":116,"line":134},[114,956,232],{"class":231},[114,958,235],{"class":231},[114,960,238],{"class":120},[114,962,242],{"class":241},[114,964,965],{"class":116,"line":143},[114,966,880],{"class":241},[114,968,969],{"class":116,"line":186},[114,970,971],{"class":241},"    database: {\n",[114,973,974,977,980],{"class":116,"line":192},[114,975,976],{"class":241},"      type: ",[114,978,979],{"class":124},"'sqlite'",[114,981,253],{"class":241},[114,983,984,987],{"class":116,"line":273},[114,985,986],{"class":241},"      filename: ",[114,988,989],{"class":124},"':memory:'\n",[114,991,992],{"class":116,"line":279},[114,993,425],{"class":241},[114,995,996],{"class":116,"line":416},[114,997,998],{"class":241},"  },\n",[114,1000,1001],{"class":116,"line":422},[114,1002,1003],{"class":241},"  routeRules: {\n",[114,1005,1006,1009,1012,1014],{"class":116,"line":428},[114,1007,1008],{"class":124},"    '\u002Fblog\u002F**'",[114,1010,1011],{"class":241},": { prerender: ",[114,1013,403],{"class":137},[114,1015,1016],{"class":241}," }\n",[114,1018,1019],{"class":116,"line":433},[114,1020,276],{"class":241},[114,1022,1024],{"class":116,"line":1023},12,[114,1025,282],{"class":241},[21,1027,1029],{"id":1028},"module-compatibility","Module Compatibility",[17,1031,1032],{},"Some Nuxt modules have known issues with Bun:",[1034,1035,1036,1049],"table",{},[1037,1038,1039],"thead",{},[1040,1041,1042,1046],"tr",{},[1043,1044,1045],"th",{},"Module",[1043,1047,1048],{},"Issue",[1050,1051,1052,1060,1068,1076,1084],"tbody",{},[1040,1053,1054,1057],{},[1055,1056,922],"td",{},[1055,1058,1059],{},"better-sqlite3 ABI mismatch",[1040,1061,1062,1065],{},[1055,1063,1064],{},"@prisma\u002Fnuxt",[1055,1066,1067],{},"Freezes during client generation",[1040,1069,1070,1073],{},[1055,1071,1072],{},"@nuxtjs\u002Fstorybook",[1055,1074,1075],{},"Fails to detect Bun as package manager",[1040,1077,1078,1081],{},[1055,1079,1080],{},"nuxt-modules\u002Fsupabase",[1055,1082,1083],{},"Installation errors",[1040,1085,1086,1089],{},[1055,1087,1088],{},"wrangler\u002Fnitro-cloudflare-dev",[1055,1090,1091],{},"Fails with Bun",[68,1093,1095],{"id":1094},"prisma-workaround","Prisma Workaround",[17,1097,1098,1099,1102],{},"Delete ",[80,1100,1101],{},"bun.lockb"," before first dev run:",[73,1104,1106],{"className":108,"code":1105,"language":110,"meta":82,"style":82},"rm bun.lockb\nbun install\nbun run dev\n",[80,1107,1108,1116,1122],{"__ignoreMap":82},[114,1109,1110,1113],{"class":116,"line":117},[114,1111,1112],{"class":120},"rm",[114,1114,1115],{"class":124}," bun.lockb\n",[114,1117,1118,1120],{"class":116,"line":134},[114,1119,146],{"class":120},[114,1121,149],{"class":124},[114,1123,1124,1126,1128],{"class":116,"line":143},[114,1125,146],{"class":120},[114,1127,174],{"class":124},[114,1129,177],{"class":124},[21,1131,1133],{"id":1132},"performance-reality","Performance Reality",[68,1135,1137],{"id":1136},"benchmarks-look-great","Benchmarks Look Great",[1034,1139,1140,1156],{},[1037,1141,1142],{},[1040,1143,1144,1147,1150,1153],{},[1043,1145,1146],{},"Metric",[1043,1148,1149],{},"Bun",[1043,1151,1152],{},"Node.js",[1043,1154,1155],{},"Improvement",[1050,1157,1158,1172,1186],{},[1040,1159,1160,1163,1166,1169],{},[1055,1161,1162],{},"HTTP Requests\u002Fsec",[1055,1164,1165],{},"~180,000",[1055,1167,1168],{},"~65,000",[1055,1170,1171],{},"2.8x",[1040,1173,1174,1177,1180,1183],{},[1055,1175,1176],{},"Package Install",[1055,1178,1179],{},"4.2x faster",[1055,1181,1182],{},"Baseline",[1055,1184,1185],{},"4.2x",[1040,1187,1188,1191,1194,1196],{},[1055,1189,1190],{},"TypeScript Transpile",[1055,1192,1193],{},"2.8x faster",[1055,1195,1182],{},[1055,1197,1171],{},[68,1199,1201],{"id":1200},"production-reality","Production Reality",[17,1203,1204],{},"Hello-world benchmarks show dramatic improvements. Standard CRUD operations show comparable performance.",[17,1206,1207],{},"Cold-start time in serverless can be higher for Bun. Memory usage may increase in some scenarios.",[17,1209,1210],{},"Test your actual workload. Benchmarks lie.",[21,1212,1214],{"id":1213},"when-to-use-bun","When to Use Bun",[68,1216,1218],{"id":1217},"good-candidates","Good Candidates",[915,1220,1221,1224,1227,1230],{},[32,1222,1223],{},"Greenfield projects — Native TypeScript, faster feedback",[32,1225,1226],{},"Side projects — Speed compounds when iterating",[32,1228,1229],{},"CI\u002FCD pipelines — 4x faster package installs matter",[32,1231,1232],{},"Serverless deployments — Lower cold-start latency",[68,1234,1236],{"id":1235},"stick-with-nodejs","Stick with Node.js",[915,1238,1239,1242,1245,1248],{},[32,1240,1241],{},"Large enterprise codebases — Migration rarely pays off",[32,1243,1244],{},"Heavy native module usage — Better compatibility",[32,1246,1247],{},"Windows development — Known socket issues",[32,1249,1250],{},"Maximum stability required — Node.js has decades of battle-testing",[21,1252,1254],{"id":1253},"production-checklist","Production Checklist",[68,1256,1258],{"id":1257},"before-deployment","Before Deployment",[29,1260,1261],{},[32,1262,1263,1264,219],{},"Lock Bun version in ",[80,1265,1266],{},"package.json",[73,1268,1272],{"className":1269,"code":1270,"language":1271,"meta":82,"style":82},"language-json shiki shiki-themes github-light github-dark","{\n  \"packageManager\": \"bun@1.3.6\"\n}\n","json",[80,1273,1274,1279,1290],{"__ignoreMap":82},[114,1275,1276],{"class":116,"line":117},[114,1277,1278],{"class":241},"{\n",[114,1280,1281,1284,1287],{"class":116,"line":134},[114,1282,1283],{"class":137},"  \"packageManager\"",[114,1285,1286],{"class":241},": ",[114,1288,1289],{"class":124},"\"bun@1.3.6\"\n",[114,1291,1292],{"class":116,"line":143},[114,1293,1294],{"class":241},"}\n",[29,1296,1297,1300,1306],{"start":134},[32,1298,1299],{},"Test all HTTP methods work",[32,1301,1302,1303],{},"Build locally first — ",[80,1304,1305],{},"NITRO_PRESET=bun bun run build",[32,1307,1308,1309],{},"Run the production build — ",[80,1310,1311],{},"bun run .output\u002Fserver\u002Findex.mjs",[68,1313,1315],{"id":1314},"docker-configuration","Docker Configuration",[73,1317,1321],{"className":1318,"code":1319,"language":1320,"meta":82,"style":82},"language-dockerfile shiki shiki-themes github-light github-dark","# Build Stage\nFROM oven\u002Fbun:1-alpine AS build\nWORKDIR \u002Fapp\nCOPY package.json bun.lock* .\u002F\nRUN bun install --frozen-lockfile --ignore-scripts\nCOPY . .\nENV NITRO_PRESET=bun\nRUN bun run build\n\n# Production Stage\nFROM oven\u002Fbun:1-alpine AS production\nWORKDIR \u002Fapp\nRUN addgroup --system --gid 1001 nuxt \\\n    && adduser --system --uid 1001 nuxt\nCOPY --from=build --chown=nuxt:nuxt \u002Fapp\u002F.output .\u002F.output\nUSER nuxt\nENV HOST=0.0.0.0\nENV PORT=3000\nEXPOSE 3000\nCMD [\"bun\", \"--bun\", \"run\", \".output\u002Fserver\u002Findex.mjs\"]\n","dockerfile",[80,1322,1323,1328,1333,1338,1343,1348,1353,1358,1363,1367,1372,1377,1381,1387,1393,1399,1405,1411,1417,1423],{"__ignoreMap":82},[114,1324,1325],{"class":116,"line":117},[114,1326,1327],{},"# Build Stage\n",[114,1329,1330],{"class":116,"line":134},[114,1331,1332],{},"FROM oven\u002Fbun:1-alpine AS build\n",[114,1334,1335],{"class":116,"line":143},[114,1336,1337],{},"WORKDIR \u002Fapp\n",[114,1339,1340],{"class":116,"line":186},[114,1341,1342],{},"COPY package.json bun.lock* .\u002F\n",[114,1344,1345],{"class":116,"line":192},[114,1346,1347],{},"RUN bun install --frozen-lockfile --ignore-scripts\n",[114,1349,1350],{"class":116,"line":273},[114,1351,1352],{},"COPY . .\n",[114,1354,1355],{"class":116,"line":279},[114,1356,1357],{},"ENV NITRO_PRESET=bun\n",[114,1359,1360],{"class":116,"line":416},[114,1361,1362],{},"RUN bun run build\n",[114,1364,1365],{"class":116,"line":422},[114,1366,183],{"emptyLinePlaceholder":182},[114,1368,1369],{"class":116,"line":428},[114,1370,1371],{},"# Production Stage\n",[114,1373,1374],{"class":116,"line":433},[114,1375,1376],{},"FROM oven\u002Fbun:1-alpine AS production\n",[114,1378,1379],{"class":116,"line":1023},[114,1380,1337],{},[114,1382,1384],{"class":116,"line":1383},13,[114,1385,1386],{},"RUN addgroup --system --gid 1001 nuxt \\\n",[114,1388,1390],{"class":116,"line":1389},14,[114,1391,1392],{},"    && adduser --system --uid 1001 nuxt\n",[114,1394,1396],{"class":116,"line":1395},15,[114,1397,1398],{},"COPY --from=build --chown=nuxt:nuxt \u002Fapp\u002F.output .\u002F.output\n",[114,1400,1402],{"class":116,"line":1401},16,[114,1403,1404],{},"USER nuxt\n",[114,1406,1408],{"class":116,"line":1407},17,[114,1409,1410],{},"ENV HOST=0.0.0.0\n",[114,1412,1414],{"class":116,"line":1413},18,[114,1415,1416],{},"ENV PORT=3000\n",[114,1418,1420],{"class":116,"line":1419},19,[114,1421,1422],{},"EXPOSE 3000\n",[114,1424,1426],{"class":116,"line":1425},20,[114,1427,1428],{},"CMD [\"bun\", \"--bun\", \"run\", \".output\u002Fserver\u002Findex.mjs\"]\n",[68,1430,1432],{"id":1431},"environment-variables","Environment Variables",[1034,1434,1435,1445],{},[1037,1436,1437],{},[1040,1438,1439,1442],{},[1043,1440,1441],{},"Variable",[1043,1443,1444],{},"Description",[1050,1446,1447,1460],{},[1040,1448,1449,1457],{},[1055,1450,1451,930,1454],{},[80,1452,1453],{},"PORT",[80,1455,1456],{},"NITRO_PORT",[1055,1458,1459],{},"Server port (default: 3000)",[1040,1461,1462,1470],{},[1055,1463,1464,930,1467],{},[80,1465,1466],{},"HOST",[80,1468,1469],{},"NITRO_HOST",[1055,1471,1472],{},"Server host (default: 0.0.0.0)",[17,1474,1475,1476,1478,1479,1481],{},"Note: ",[80,1477,1469],{}," may not work with the Bun preset. Only ",[80,1480,1456],{}," is reliable.",[21,1483,1485],{"id":1484},"testing-setup","Testing Setup",[68,1487,1489],{"id":1488},"vitest-configuration","Vitest Configuration",[73,1491,1493],{"className":222,"code":1492,"language":224,"meta":82,"style":82},"\u002F\u002F vitest.config.ts\nimport { defineVitestConfig } from '@nuxt\u002Ftest-utils\u002Fconfig'\n\nexport default defineVitestConfig({\n  test: {\n    environment: 'nuxt',\n    environmentOptions: {\n      nuxt: {\n        domEnvironment: 'happy-dom'\n      }\n    }\n  }\n})\n",[80,1494,1495,1500,1512,1516,1527,1532,1542,1547,1552,1560,1564,1568,1572],{"__ignoreMap":82},[114,1496,1497],{"class":116,"line":117},[114,1498,1499],{"class":166},"\u002F\u002F vitest.config.ts\n",[114,1501,1502,1504,1507,1509],{"class":116,"line":134},[114,1503,587],{"class":231},[114,1505,1506],{"class":241}," { defineVitestConfig } ",[114,1508,593],{"class":231},[114,1510,1511],{"class":124}," '@nuxt\u002Ftest-utils\u002Fconfig'\n",[114,1513,1514],{"class":116,"line":143},[114,1515,183],{"emptyLinePlaceholder":182},[114,1517,1518,1520,1522,1525],{"class":116,"line":186},[114,1519,232],{"class":231},[114,1521,235],{"class":231},[114,1523,1524],{"class":120}," defineVitestConfig",[114,1526,242],{"class":241},[114,1528,1529],{"class":116,"line":192},[114,1530,1531],{"class":241},"  test: {\n",[114,1533,1534,1537,1540],{"class":116,"line":273},[114,1535,1536],{"class":241},"    environment: ",[114,1538,1539],{"class":124},"'nuxt'",[114,1541,253],{"class":241},[114,1543,1544],{"class":116,"line":279},[114,1545,1546],{"class":241},"    environmentOptions: {\n",[114,1548,1549],{"class":116,"line":416},[114,1550,1551],{"class":241},"      nuxt: {\n",[114,1553,1554,1557],{"class":116,"line":422},[114,1555,1556],{"class":241},"        domEnvironment: ",[114,1558,1559],{"class":124},"'happy-dom'\n",[114,1561,1562],{"class":116,"line":428},[114,1563,419],{"class":241},[114,1565,1566],{"class":116,"line":433},[114,1567,425],{"class":241},[114,1569,1570],{"class":116,"line":1023},[114,1571,276],{"class":241},[114,1573,1574],{"class":116,"line":1383},[114,1575,282],{"class":241},[68,1577,1579],{"id":1578},"running-tests","Running Tests",[73,1581,1583],{"className":108,"code":1582,"language":110,"meta":82,"style":82},"bun run test\nbun run test:e2e\n",[80,1584,1585,1594],{"__ignoreMap":82},[114,1586,1587,1589,1591],{"class":116,"line":117},[114,1588,146],{"class":120},[114,1590,174],{"class":124},[114,1592,1593],{"class":124}," test\n",[114,1595,1596,1598,1600],{"class":116,"line":134},[114,1597,146],{"class":120},[114,1599,174],{"class":124},[114,1601,1602],{"class":124}," test:e2e\n",[21,1604,1606],{"id":1605},"practical-recommendation","Practical Recommendation",[17,1608,1609],{},"Use Bun as a package manager. Run development with Node.js. Deploy production with the Bun preset.",[73,1611,1613],{"className":108,"code":1612,"language":110,"meta":82,"style":82},"# Install with Bun (fast)\nbun install\n\n# Develop with Node.js (stable)\nbun run dev\n\n# Build for Bun runtime\nNITRO_PRESET=bun bun run build\n\n# Run production\nbun run .output\u002Fserver\u002Findex.mjs\n",[80,1614,1615,1620,1626,1630,1635,1643,1647,1652,1666,1670,1675],{"__ignoreMap":82},[114,1616,1617],{"class":116,"line":117},[114,1618,1619],{"class":166},"# Install with Bun (fast)\n",[114,1621,1622,1624],{"class":116,"line":134},[114,1623,146],{"class":120},[114,1625,149],{"class":124},[114,1627,1628],{"class":116,"line":143},[114,1629,183],{"emptyLinePlaceholder":182},[114,1631,1632],{"class":116,"line":186},[114,1633,1634],{"class":166},"# Develop with Node.js (stable)\n",[114,1636,1637,1639,1641],{"class":116,"line":192},[114,1638,146],{"class":120},[114,1640,174],{"class":124},[114,1642,177],{"class":124},[114,1644,1645],{"class":116,"line":273},[114,1646,183],{"emptyLinePlaceholder":182},[114,1648,1649],{"class":116,"line":279},[114,1650,1651],{"class":166},"# Build for Bun runtime\n",[114,1653,1654,1656,1658,1660,1662,1664],{"class":116,"line":416},[114,1655,295],{"class":241},[114,1657,298],{"class":231},[114,1659,146],{"class":124},[114,1661,303],{"class":120},[114,1663,174],{"class":124},[114,1665,308],{"class":124},[114,1667,1668],{"class":116,"line":422},[114,1669,183],{"emptyLinePlaceholder":182},[114,1671,1672],{"class":116,"line":428},[114,1673,1674],{"class":166},"# Run production\n",[114,1676,1677,1679,1681],{"class":116,"line":433},[114,1678,146],{"class":120},[114,1680,174],{"class":124},[114,1682,1683],{"class":124}," .output\u002Fserver\u002Findex.mjs\n",[17,1685,1686],{},"This approach gives you faster installs without the development instability.",[21,1688,1690],{"id":1689},"summary","Summary",[17,1692,1693],{},"Bun with Nuxt 4 works. It is not seamless.",[29,1695,1696,1699,1705,1711,1714,1717],{},[32,1697,1698],{},"Use Bun 1.3.6 with Nuxt 4.2.2 (latest stable)",[32,1700,1701,1702,1704],{},"Set ",[80,1703,698],{}," for production",[32,1706,1707,1708,1710],{},"Avoid ",[80,1709,207],{}," flag in development if you hit issues",[32,1712,1713],{},"Test all HTTP methods before deploying",[32,1715,1716],{},"Use WSL on Windows",[32,1718,1719],{},"Watch for memory leaks in long dev sessions",[17,1721,1722],{},"The performance gains are real. The edge cases are also real. Know both before committing.",[21,1724,1726],{"id":1725},"references","References",[1728,1729,1730,1736],"utilities-fields",{},[1731,1732,1733],"template",{"v-slot:title":82},[17,1734,1735],{},"Nuxt 4 Documentation",[1731,1737,1738],{"v-slot:content":82},[17,1739,1740,1745],{},[484,1741,1744],{"href":1742,"rel":1743},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002F4.x\u002Fgetting-started\u002Finstallation",[488],"nuxt.com"," — Official installation and deployment guides",[1728,1747,1748,1753],{},[1731,1749,1750],{"v-slot:title":82},[17,1751,1752],{},"Bun + Nuxt Guide",[1731,1754,1755],{"v-slot:content":82},[17,1756,1757,1762],{},[484,1758,1761],{"href":1759,"rel":1760},"https:\u002F\u002Fbun.com\u002Fguides\u002Fecosystem\u002Fnuxt",[488],"bun.com"," — Official Bun documentation for Nuxt",[1728,1764,1765,1770],{},[1731,1766,1767],{"v-slot:title":82},[17,1768,1769],{},"Nitro Bun Runtime",[1731,1771,1772],{"v-slot:content":82},[17,1773,1774,1779],{},[484,1775,1778],{"href":1776,"rel":1777},"https:\u002F\u002Fnitro.build\u002Fdeploy\u002Fruntimes\u002Fbun",[488],"nitro.build"," — Nitro preset documentation",[1728,1781,1782,1787],{},[1731,1783,1784],{"v-slot:title":82},[17,1785,1786],{},"GitHub Issue #32875",[1731,1788,1789],{"v-slot:content":82},[17,1790,1791,1796],{},[484,1792,1795],{"href":1793,"rel":1794},"https:\u002F\u002Fgithub.com\u002Fnuxt\u002Fnuxt\u002Fissues\u002F32875",[488],"github.com"," — Unable to run Nuxt 4 on Bun tracking issue",[1728,1798,1799,1804],{},[1731,1800,1801],{"v-slot:title":82},[17,1802,1803],{},"GitHub Issue #21762",[1731,1805,1806],{"v-slot:content":82},[17,1807,1808,1812],{},[484,1809,1795],{"href":1810,"rel":1811},"https:\u002F\u002Fgithub.com\u002Foven-sh\u002Fbun\u002Fissues\u002F21762",[488]," — Bun version compatibility tracking",[1728,1814,1815,1819],{},[1731,1816,1817],{"v-slot:title":82},[17,1818,489],{},[1731,1820,1821],{"v-slot:content":82},[17,1822,1823,1826],{},[484,1824,1795],{"href":486,"rel":1825},[488]," — Memory leak in dev mode",[1728,1828,1829,1834],{},[1731,1830,1831],{"v-slot:title":82},[17,1832,1833],{},"GitHub Issue #31249",[1731,1835,1836],{"v-slot:content":82},[17,1837,1838,1842],{},[484,1839,1795],{"href":1840,"rel":1841},"https:\u002F\u002Fgithub.com\u002Fnuxt\u002Fnuxt\u002Fissues\u002F31249",[488]," — HMR breaks with Bun runtime",[1728,1844,1845,1849],{},[1731,1846,1847],{"v-slot:title":82},[17,1848,807],{},[1731,1850,1851],{"v-slot:content":82},[17,1852,1853,1856],{},[484,1854,1795],{"href":805,"rel":1855},[488]," — Nuxt Content better-sqlite3 doesn't work with Bun",[1728,1858,1859,1864],{},[1731,1860,1861],{"v-slot:title":82},[17,1862,1863],{},"GitHub Issue #3118",[1731,1865,1866],{"v-slot:content":82},[17,1867,1868,1871],{},[484,1869,1795],{"href":811,"rel":1870},[488]," — bunsqlite polyfills regression",[1873,1874,1875],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":82,"searchDepth":134,"depth":134,"links":1877},[1878,1879,1882,1888,1896,1901,1907,1910,1914,1918,1923,1927,1928,1929],{"id":23,"depth":134,"text":24},{"id":59,"depth":134,"text":60,"children":1880},[1881],{"id":70,"depth":143,"text":71},{"id":97,"depth":134,"text":98,"children":1883},[1884,1885,1886,1887],{"id":101,"depth":143,"text":102},{"id":152,"depth":143,"text":153},{"id":211,"depth":143,"text":212},{"id":311,"depth":143,"text":312},{"id":326,"depth":134,"text":327,"children":1889},[1890,1891,1892,1893,1894,1895],{"id":330,"depth":143,"text":331},{"id":343,"depth":143,"text":344},{"id":438,"depth":143,"text":439},{"id":448,"depth":143,"text":449},{"id":464,"depth":143,"text":465},{"id":493,"depth":143,"text":494},{"id":561,"depth":134,"text":562,"children":1897},[1898,1899,1900],{"id":571,"depth":143,"text":572},{"id":680,"depth":143,"text":681},{"id":707,"depth":143,"text":708},{"id":767,"depth":134,"text":768,"children":1902},[1903,1904,1905,1906],{"id":774,"depth":143,"text":775},{"id":791,"depth":143,"text":60},{"id":816,"depth":143,"text":817},{"id":939,"depth":143,"text":940},{"id":1028,"depth":134,"text":1029,"children":1908},[1909],{"id":1094,"depth":143,"text":1095},{"id":1132,"depth":134,"text":1133,"children":1911},[1912,1913],{"id":1136,"depth":143,"text":1137},{"id":1200,"depth":143,"text":1201},{"id":1213,"depth":134,"text":1214,"children":1915},[1916,1917],{"id":1217,"depth":143,"text":1218},{"id":1235,"depth":143,"text":1236},{"id":1253,"depth":134,"text":1254,"children":1919},[1920,1921,1922],{"id":1257,"depth":143,"text":1258},{"id":1314,"depth":143,"text":1315},{"id":1431,"depth":143,"text":1432},{"id":1484,"depth":134,"text":1485,"children":1924},[1925,1926],{"id":1488,"depth":143,"text":1489},{"id":1578,"depth":143,"text":1579},{"id":1605,"depth":134,"text":1606},{"id":1689,"depth":134,"text":1690},{"id":1725,"depth":134,"text":1726},null,"2026-01-15","Practical guide to using Bun with Nuxt 4 in production. Configuration, known issues, performance gains, and when to stick with Node.js.",false,"mdc","Bun + Nuxt 4 Guide",{},"\u002Fblog\u002Fbun-nuxt4-runtime-guide",{"title":6,"description":1932},"blog\u002Fbun-nuxt4-runtime-guide",[146,1941,1942,1943,1944],"nuxt","runtime","performance","node","swiss_precision","Ldx54_8uQ5Ys7Zpl8QClz9AQFwF2A-0XQo4mgeyuQX8",[1948,1930],{"id":1949,"title":1950,"author":7,"body":1951,"brandColor":1930,"colorBg":1930,"colorBgSecondary":1930,"colorBrand":1930,"colorFooter":1930,"colorFooterText":1930,"colorHeaders":1930,"colorInvertedText":1930,"colorText":1930,"colorTopbar":1930,"coverImage":1930,"date":1931,"description":2960,"draft":1933,"extension":1934,"galleryDark":1933,"galleryImage":1930,"gallerySize":1930,"h1":2961,"hoverVideo":1930,"label":2962,"meta":2963,"navigation":182,"order":117,"path":2964,"seo":2965,"stem":2966,"tags":2967,"theme":1945,"__hash__":2972},"blog\u002Fblog\u002Fios26-safari-toolbar-colors.mdc","Why iOS 26 Safari Toolbar Colors Work Differently - Ben Nasedkin",{"type":9,"value":1952,"toc":2932},[1953,1957,1964,1967,1971,1977,2012,2015,2018,2021,2043,2046,2050,2053,2057,2060,2066,2069,2073,2076,2079,2083,2086,2091,2095,2098,2102,2115,2174,2177,2180,2184,2190,2220,2223,2232,2292,2296,2299,2306,2310,2313,2317,2320,2390,2393,2397,2400,2501,2505,2511,2514,2518,2522,2525,2528,2532,2535,2633,2636,2640,2643,2742,2745,2749,2752,2755,2759,2762,2776,2779,2783,2786,2789,2792,2795,2798,2800,2822,2825,2827,2844,2861,2878,2895,2912,2929],[12,1954,1956],{"id":1955},"why-ios-26-safari-toolbar-colors-work-differently","Why iOS 26 Safari Toolbar Colors Work Differently",[17,1958,1959,1960,1963],{},"If you've updated to iOS 26, you've noticed. The Safari toolbar looks different. Colors shift as you scroll. Your carefully chosen ",[80,1961,1962],{},"theme-color"," meta tag does nothing.",[17,1965,1966],{},"This isn't a bug. It's a philosophy shift.",[21,1968,1970],{"id":1969},"what-changed","What Changed",[17,1972,1973,1974,1976],{},"Safari 15 through 18.6 supported the ",[80,1975,1962],{}," meta tag:",[73,1978,1982],{"className":1979,"code":1980,"language":1981,"meta":82,"style":82},"language-html shiki shiki-themes github-light github-dark","\u003Cmeta name=\"theme-color\" content=\"#1a1a1a\">\n","html",[80,1983,1984],{"__ignoreMap":82},[114,1985,1986,1989,1993,1996,1998,2001,2004,2006,2009],{"class":116,"line":117},[114,1987,1988],{"class":241},"\u003C",[114,1990,1992],{"class":1991},"s9eBZ","meta",[114,1994,1995],{"class":120}," name",[114,1997,298],{"class":241},[114,1999,2000],{"class":124},"\"theme-color\"",[114,2002,2003],{"class":120}," content",[114,2005,298],{"class":241},[114,2007,2008],{"class":124},"\"#1a1a1a\"",[114,2010,2011],{"class":241},">\n",[17,2013,2014],{},"Developers declared toolbar colors explicitly. Simple, predictable, controllable.",[17,2016,2017],{},"Safari 26 dropped this. The meta tag still parses — Safari ignores the value.",[17,2019,2020],{},"Instead, Safari now derives toolbar colors automatically from your CSS:",[29,2022,2023,2030,2040],{},[32,2024,2025,2026,2029],{},"First, from the ",[80,2027,2028],{},"background-color"," of fixed or sticky elements near the viewport edges",[32,2031,2032,2033,2035,2036,2039],{},"Fallback to the ",[80,2034,2028],{}," of the ",[80,2037,2038],{},"\u003Cbody>"," element",[32,2041,2042],{},"If neither exists, system default",[17,2044,2045],{},"This happens at render time. JavaScript changes to background colors after initial paint don't update the toolbar.",[21,2047,2049],{"id":2048},"why-apple-made-this-change","Why Apple Made This Change",[17,2051,2052],{},"The answer is Liquid Glass.",[68,2054,2056],{"id":2055},"content-first-design","Content-First Design",[17,2058,2059],{},"Apple's new design language prioritizes content over chrome. The interface should disappear during use, not demand attention.",[17,2061,2062,2063,2065],{},"A hardcoded ",[80,2064,1962],{}," creates a static toolbar. It doesn't respond to content. It competes with it.",[17,2067,2068],{},"By deriving colors from actual page elements, the toolbar becomes contextual. It reflects what you're looking at, not what the developer decided months ago.",[68,2070,2072],{"id":2071},"dynamic-immersion","Dynamic Immersion",[17,2074,2075],{},"On iOS 26, the address bar blends with the webpage. On macOS Tahoe, toolbars reflect page colors as you scroll. The UI feels alive.",[17,2077,2078],{},"This only works if Safari controls the color derivation. A static meta tag breaks the illusion.",[68,2080,2082],{"id":2081},"cross-platform-consistency","Cross-Platform Consistency",[17,2084,2085],{},"Liquid Glass spans iOS, iPadOS, macOS, watchOS, and tvOS. A unified visual language requires unified behavior.",[17,2087,204,2088,2090],{},[80,2089,1962],{}," meta tag was a web-only concept. Dropping it aligns Safari with native app behavior, where system chrome adapts to content automatically.",[21,2092,2094],{"id":2093},"the-derivation-logic","The Derivation Logic",[17,2096,2097],{},"Safari's color algorithm follows a specific hierarchy.",[68,2099,2101],{"id":2100},"fixed-and-sticky-elements-take-priority","Fixed and Sticky Elements Take Priority",[17,2103,2104,2105,930,2108,2111,2112,2114],{},"If you have a header with ",[80,2106,2107],{},"position: fixed",[80,2109,2110],{},"position: sticky"," near the top of the viewport, Safari samples its ",[80,2113,2028],{}," for the toolbar.",[73,2116,2120],{"className":2117,"code":2118,"language":2119,"meta":82,"style":82},"language-css shiki shiki-themes github-light github-dark","header {\n  position: fixed;\n  top: 0;\n  background-color: #1a1a1a; \u002F* This becomes toolbar color *\u002F\n}\n","css",[80,2121,2122,2129,2142,2154,2170],{"__ignoreMap":82},[114,2123,2124,2127],{"class":116,"line":117},[114,2125,2126],{"class":1991},"header",[114,2128,648],{"class":241},[114,2130,2131,2134,2136,2139],{"class":116,"line":134},[114,2132,2133],{"class":137},"  position",[114,2135,1286],{"class":241},[114,2137,2138],{"class":137},"fixed",[114,2140,2141],{"class":241},";\n",[114,2143,2144,2147,2149,2152],{"class":116,"line":143},[114,2145,2146],{"class":137},"  top",[114,2148,1286],{"class":241},[114,2150,2151],{"class":137},"0",[114,2153,2141],{"class":241},[114,2155,2156,2159,2161,2164,2167],{"class":116,"line":186},[114,2157,2158],{"class":137},"  background-color",[114,2160,1286],{"class":241},[114,2162,2163],{"class":137},"#1a1a1a",[114,2165,2166],{"class":241},"; ",[114,2168,2169],{"class":166},"\u002F* This becomes toolbar color *\u002F\n",[114,2171,2172],{"class":116,"line":192},[114,2173,1294],{"class":241},[17,2175,2176],{},"The logic: fixed elements border the \"obscured content inset\" — the area where browser UI overlaps your content. Safari extends the fixed element's color into the toolbar to create visual continuity.",[17,2178,2179],{},"This matters more on iPhone. The blur effect under the toolbar is softer than on macOS. More of your page shows through. Color mismatches become jarring.",[68,2181,2183],{"id":2182},"body-background-as-fallback","Body Background as Fallback",[17,2185,2186,2187,2189],{},"Without fixed elements, Safari falls back to ",[80,2188,2038],{}," background color.",[73,2191,2193],{"className":2117,"code":2192,"language":2119,"meta":82,"style":82},"body {\n  background-color: #ffffff; \u002F* Toolbar color if no fixed elements *\u002F\n}\n",[80,2194,2195,2202,2216],{"__ignoreMap":82},[114,2196,2197,2200],{"class":116,"line":117},[114,2198,2199],{"class":1991},"body",[114,2201,648],{"class":241},[114,2203,2204,2206,2208,2211,2213],{"class":116,"line":134},[114,2205,2158],{"class":137},[114,2207,1286],{"class":241},[114,2209,2210],{"class":137},"#ffffff",[114,2212,2166],{"class":241},[114,2214,2215],{"class":166},"\u002F* Toolbar color if no fixed elements *\u002F\n",[114,2217,2218],{"class":116,"line":143},[114,2219,1294],{"class":241},[17,2221,2222],{},"This is also what determines the overscroll \"rubber band\" color. When users pull past the content boundary, they see the body background. Safari uses the same value for toolbar tinting.",[17,2224,1475,2225,2228,2229,2231],{},[80,2226,2227],{},"\u003Chtml>"," background is ignored for this purpose. Only ",[80,2230,2038],{}," matters.",[73,2233,2235],{"className":2117,"code":2234,"language":2119,"meta":82,"style":82},"\u002F* This does NOT affect toolbar or overscroll *\u002F\nhtml {\n  background-color: #ff0000;\n}\n\n\u002F* This DOES affect toolbar and overscroll *\u002F\nbody {\n  background-color: #1a1a1a;\n}\n",[80,2236,2237,2242,2248,2259,2263,2267,2272,2278,2288],{"__ignoreMap":82},[114,2238,2239],{"class":116,"line":117},[114,2240,2241],{"class":166},"\u002F* This does NOT affect toolbar or overscroll *\u002F\n",[114,2243,2244,2246],{"class":116,"line":134},[114,2245,1981],{"class":1991},[114,2247,648],{"class":241},[114,2249,2250,2252,2254,2257],{"class":116,"line":143},[114,2251,2158],{"class":137},[114,2253,1286],{"class":241},[114,2255,2256],{"class":137},"#ff0000",[114,2258,2141],{"class":241},[114,2260,2261],{"class":116,"line":186},[114,2262,1294],{"class":241},[114,2264,2265],{"class":116,"line":192},[114,2266,183],{"emptyLinePlaceholder":182},[114,2268,2269],{"class":116,"line":273},[114,2270,2271],{"class":166},"\u002F* This DOES affect toolbar and overscroll *\u002F\n",[114,2273,2274,2276],{"class":116,"line":279},[114,2275,2199],{"class":1991},[114,2277,648],{"class":241},[114,2279,2280,2282,2284,2286],{"class":116,"line":416},[114,2281,2158],{"class":137},[114,2283,1286],{"class":241},[114,2285,2163],{"class":137},[114,2287,2141],{"class":241},[114,2289,2290],{"class":116,"line":422},[114,2291,1294],{"class":241},[68,2293,2295],{"id":2294},"the-rendering-window","The Rendering Window",[17,2297,2298],{},"Safari samples colors at initial render. Changes via JavaScript don't trigger re-sampling.",[17,2300,2301,2302,2305],{},"If you dynamically change ",[80,2303,2304],{},"document.body.style.backgroundColor",", the toolbar won't update. This is intentional — constant toolbar color changes would be visually chaotic.",[21,2307,2309],{"id":2308},"the-problems-this-creates","The Problems This Creates",[17,2311,2312],{},"Apple's logic makes sense in theory. In practice, edge cases break.",[68,2314,2316],{"id":2315},"dialog-and-popover-conflicts","Dialog and Popover Conflicts",[17,2318,2319],{},"When you show a modal with a semi-transparent backdrop, Safari might sample the backdrop's background color for the toolbar.",[73,2321,2323],{"className":2117,"code":2322,"language":2119,"meta":82,"style":82},".modal-backdrop {\n  position: fixed;\n  inset: 0;\n  background-color: rgba(0, 0, 0, 0.5); \u002F* Safari may sample this *\u002F\n}\n",[80,2324,2325,2332,2342,2353,2386],{"__ignoreMap":82},[114,2326,2327,2330],{"class":116,"line":117},[114,2328,2329],{"class":120},".modal-backdrop",[114,2331,648],{"class":241},[114,2333,2334,2336,2338,2340],{"class":116,"line":134},[114,2335,2133],{"class":137},[114,2337,1286],{"class":241},[114,2339,2138],{"class":137},[114,2341,2141],{"class":241},[114,2343,2344,2347,2349,2351],{"class":116,"line":143},[114,2345,2346],{"class":137},"  inset",[114,2348,1286],{"class":241},[114,2350,2151],{"class":137},[114,2352,2141],{"class":241},[114,2354,2355,2357,2359,2362,2364,2366,2369,2371,2373,2375,2377,2380,2383],{"class":116,"line":186},[114,2356,2158],{"class":137},[114,2358,1286],{"class":241},[114,2360,2361],{"class":137},"rgba",[114,2363,620],{"class":241},[114,2365,2151],{"class":137},[114,2367,2368],{"class":241},", ",[114,2370,2151],{"class":137},[114,2372,2368],{"class":241},[114,2374,2151],{"class":137},[114,2376,2368],{"class":241},[114,2378,2379],{"class":137},"0.5",[114,2381,2382],{"class":241},"); ",[114,2384,2385],{"class":166},"\u002F* Safari may sample this *\u002F\n",[114,2387,2388],{"class":116,"line":192},[114,2389,1294],{"class":241},[17,2391,2392],{},"Your dark overlay suddenly tints the entire toolbar dark — even though your actual content underneath is light.",[68,2394,2396],{"id":2395},"multiple-fixed-elements","Multiple Fixed Elements",[17,2398,2399],{},"If you have both a fixed header and a fixed footer, Safari picks one. The algorithm isn't always predictable.",[73,2401,2403],{"className":2117,"code":2402,"language":2119,"meta":82,"style":82},".header {\n  position: fixed;\n  top: 0;\n  background-color: #ffffff;\n}\n\n.footer {\n  position: fixed;\n  bottom: 0;\n  background-color: #1a1a1a;\n}\n\n\u002F* Which color wins? Safari decides. *\u002F\n",[80,2404,2405,2412,2422,2432,2442,2446,2450,2457,2467,2478,2488,2492,2496],{"__ignoreMap":82},[114,2406,2407,2410],{"class":116,"line":117},[114,2408,2409],{"class":120},".header",[114,2411,648],{"class":241},[114,2413,2414,2416,2418,2420],{"class":116,"line":134},[114,2415,2133],{"class":137},[114,2417,1286],{"class":241},[114,2419,2138],{"class":137},[114,2421,2141],{"class":241},[114,2423,2424,2426,2428,2430],{"class":116,"line":143},[114,2425,2146],{"class":137},[114,2427,1286],{"class":241},[114,2429,2151],{"class":137},[114,2431,2141],{"class":241},[114,2433,2434,2436,2438,2440],{"class":116,"line":186},[114,2435,2158],{"class":137},[114,2437,1286],{"class":241},[114,2439,2210],{"class":137},[114,2441,2141],{"class":241},[114,2443,2444],{"class":116,"line":192},[114,2445,1294],{"class":241},[114,2447,2448],{"class":116,"line":273},[114,2449,183],{"emptyLinePlaceholder":182},[114,2451,2452,2455],{"class":116,"line":279},[114,2453,2454],{"class":120},".footer",[114,2456,648],{"class":241},[114,2458,2459,2461,2463,2465],{"class":116,"line":416},[114,2460,2133],{"class":137},[114,2462,1286],{"class":241},[114,2464,2138],{"class":137},[114,2466,2141],{"class":241},[114,2468,2469,2472,2474,2476],{"class":116,"line":422},[114,2470,2471],{"class":137},"  bottom",[114,2473,1286],{"class":241},[114,2475,2151],{"class":137},[114,2477,2141],{"class":241},[114,2479,2480,2482,2484,2486],{"class":116,"line":428},[114,2481,2158],{"class":137},[114,2483,1286],{"class":241},[114,2485,2163],{"class":137},[114,2487,2141],{"class":241},[114,2489,2490],{"class":116,"line":433},[114,2491,1294],{"class":241},[114,2493,2494],{"class":116,"line":1023},[114,2495,183],{"emptyLinePlaceholder":182},[114,2497,2498],{"class":116,"line":1383},[114,2499,2500],{"class":166},"\u002F* Which color wins? Safari decides. *\u002F\n",[68,2502,2504],{"id":2503},"no-override-mechanism","No Override Mechanism",[17,2506,2507,2508,2510],{},"Unlike ",[80,2509,1962],{},", you can't explicitly tell Safari what color to use. You're at the mercy of the derivation algorithm.",[17,2512,2513],{},"If your design requires a specific toolbar color that doesn't match any element's background, you have no clean solution.",[21,2515,2517],{"id":2516},"what-this-means-for-design","What This Means for Design",[68,2519,2521],{"id":2520},"design-with-derivation-in-mind","Design with derivation in mind",[17,2523,2524],{},"Your fixed header's background color is now your toolbar color. Plan accordingly.",[17,2526,2527],{},"If you want a white toolbar, your header needs a white (or near-white) background. If you want the toolbar to match your brand color, that color needs to exist on a fixed element.",[68,2529,2531],{"id":2530},"transparency-is-risky","Transparency is risky",[17,2533,2534],{},"Semi-transparent backgrounds on fixed elements create unpredictable toolbar colors. Safari samples the computed color, which depends on what's behind the transparent layer.",[73,2536,2538],{"className":2117,"code":2537,"language":2119,"meta":82,"style":82},"\u002F* Unpredictable — computed color depends on content behind *\u002F\nheader {\n  position: fixed;\n  background-color: rgba(255, 255, 255, 0.8);\n}\n\n\u002F* Predictable — Safari gets exactly this color *\u002F\nheader {\n  position: fixed;\n  background-color: #ffffff;\n}\n",[80,2539,2540,2545,2551,2561,2590,2594,2598,2603,2609,2619,2629],{"__ignoreMap":82},[114,2541,2542],{"class":116,"line":117},[114,2543,2544],{"class":166},"\u002F* Unpredictable — computed color depends on content behind *\u002F\n",[114,2546,2547,2549],{"class":116,"line":134},[114,2548,2126],{"class":1991},[114,2550,648],{"class":241},[114,2552,2553,2555,2557,2559],{"class":116,"line":143},[114,2554,2133],{"class":137},[114,2556,1286],{"class":241},[114,2558,2138],{"class":137},[114,2560,2141],{"class":241},[114,2562,2563,2565,2567,2569,2571,2574,2576,2578,2580,2582,2584,2587],{"class":116,"line":186},[114,2564,2158],{"class":137},[114,2566,1286],{"class":241},[114,2568,2361],{"class":137},[114,2570,620],{"class":241},[114,2572,2573],{"class":137},"255",[114,2575,2368],{"class":241},[114,2577,2573],{"class":137},[114,2579,2368],{"class":241},[114,2581,2573],{"class":137},[114,2583,2368],{"class":241},[114,2585,2586],{"class":137},"0.8",[114,2588,2589],{"class":241},");\n",[114,2591,2592],{"class":116,"line":192},[114,2593,1294],{"class":241},[114,2595,2596],{"class":116,"line":273},[114,2597,183],{"emptyLinePlaceholder":182},[114,2599,2600],{"class":116,"line":279},[114,2601,2602],{"class":166},"\u002F* Predictable — Safari gets exactly this color *\u002F\n",[114,2604,2605,2607],{"class":116,"line":416},[114,2606,2126],{"class":1991},[114,2608,648],{"class":241},[114,2610,2611,2613,2615,2617],{"class":116,"line":422},[114,2612,2133],{"class":137},[114,2614,1286],{"class":241},[114,2616,2138],{"class":137},[114,2618,2141],{"class":241},[114,2620,2621,2623,2625,2627],{"class":116,"line":428},[114,2622,2158],{"class":137},[114,2624,1286],{"class":241},[114,2626,2210],{"class":137},[114,2628,2141],{"class":241},[114,2630,2631],{"class":116,"line":433},[114,2632,1294],{"class":241},[17,2634,2635],{},"Solid colors give you control. Transparency gives Safari control.",[68,2637,2639],{"id":2638},"test-the-overscroll","Test the overscroll",[17,2641,2642],{},"Pull up and down on your page. Watch what color appears in the rubber band effect. That's your body background. That's also influencing your toolbar.",[73,2644,2646],{"className":2117,"code":2645,"language":2119,"meta":82,"style":82},"\u002F* Dark site with white overscroll — jarring *\u002F\nbody {\n  background-color: #ffffff;\n}\n\n.page-wrapper {\n  background-color: #1a1a1a;\n  min-height: 100vh;\n}\n\n\u002F* Dark site with matching overscroll — seamless *\u002F\nbody {\n  background-color: #1a1a1a;\n}\n",[80,2647,2648,2653,2659,2669,2673,2677,2684,2694,2709,2713,2717,2722,2728,2738],{"__ignoreMap":82},[114,2649,2650],{"class":116,"line":117},[114,2651,2652],{"class":166},"\u002F* Dark site with white overscroll — jarring *\u002F\n",[114,2654,2655,2657],{"class":116,"line":134},[114,2656,2199],{"class":1991},[114,2658,648],{"class":241},[114,2660,2661,2663,2665,2667],{"class":116,"line":143},[114,2662,2158],{"class":137},[114,2664,1286],{"class":241},[114,2666,2210],{"class":137},[114,2668,2141],{"class":241},[114,2670,2671],{"class":116,"line":186},[114,2672,1294],{"class":241},[114,2674,2675],{"class":116,"line":192},[114,2676,183],{"emptyLinePlaceholder":182},[114,2678,2679,2682],{"class":116,"line":273},[114,2680,2681],{"class":120},".page-wrapper",[114,2683,648],{"class":241},[114,2685,2686,2688,2690,2692],{"class":116,"line":279},[114,2687,2158],{"class":137},[114,2689,1286],{"class":241},[114,2691,2163],{"class":137},[114,2693,2141],{"class":241},[114,2695,2696,2699,2701,2704,2707],{"class":116,"line":416},[114,2697,2698],{"class":137},"  min-height",[114,2700,1286],{"class":241},[114,2702,2703],{"class":137},"100",[114,2705,2706],{"class":231},"vh",[114,2708,2141],{"class":241},[114,2710,2711],{"class":116,"line":422},[114,2712,1294],{"class":241},[114,2714,2715],{"class":116,"line":428},[114,2716,183],{"emptyLinePlaceholder":182},[114,2718,2719],{"class":116,"line":433},[114,2720,2721],{"class":166},"\u002F* Dark site with matching overscroll — seamless *\u002F\n",[114,2723,2724,2726],{"class":116,"line":1023},[114,2725,2199],{"class":1991},[114,2727,648],{"class":241},[114,2729,2730,2732,2734,2736],{"class":116,"line":1383},[114,2731,2158],{"class":137},[114,2733,1286],{"class":241},[114,2735,2163],{"class":137},[114,2737,2141],{"class":241},[114,2739,2740],{"class":116,"line":1389},[114,2741,1294],{"class":241},[17,2743,2744],{},"If your body background is white but your design is dark, you'll see jarring white flashes during overscroll.",[68,2746,2748],{"id":2747},"accept-the-constraint","Accept the constraint",[17,2750,2751],{},"Apple made a design decision. Fighting it creates more problems than accepting it.",[17,2753,2754],{},"Design your fixed elements with toolbar tinting in mind. Choose body backgrounds that work for overscroll. Let Safari do its thing.",[21,2756,2758],{"id":2757},"user-controls","User Controls",[17,2760,2761],{},"Users can disable color tinting entirely:",[915,2763,2764,2770],{},[32,2765,2766,2769],{},[35,2767,2768],{},"macOS:"," Safari → Settings → Tabs → Appearance → \"Show color in tab bar\"",[32,2771,2772,2775],{},[35,2773,2774],{},"iOS:"," Settings → Apps → Safari → Tabs → \"Allow Website Tinting\"",[17,2777,2778],{},"When disabled, toolbars revert to system default colors. Your design should still work in this mode.",[21,2780,2782],{"id":2781},"the-bigger-picture","The Bigger Picture",[17,2784,2785],{},"Apple is betting that automated, context-aware UI is better than explicit developer control.",[17,2787,2788],{},"For most sites, this works. The toolbar picks up reasonable colors. The interface feels cohesive.",[17,2790,2791],{},"For sites with complex designs, multiple themes, or specific brand requirements, it's a constraint.",[17,2793,2794],{},"The web has always been about negotiating control between browsers and developers. iOS 26 shifts that balance toward the browser.",[17,2796,2797],{},"Whether that's progress depends on your perspective.",[21,2799,1690],{"id":1689},[29,2801,2802,2807,2810,2813,2816,2819],{},[32,2803,2804,2806],{},[80,2805,1962],{}," meta tag is ignored in Safari 26+",[32,2808,2809],{},"Safari derives toolbar colors from fixed\u002Fsticky element backgrounds, then body background",[32,2811,2812],{},"This serves Apple's Liquid Glass design philosophy — content-first, dynamic, immersive",[32,2814,2815],{},"Color sampling happens at render time — JavaScript changes don't update the toolbar",[32,2817,2818],{},"Design your fixed elements knowing they determine toolbar color",[32,2820,2821],{},"Users can disable tinting entirely",[17,2823,2824],{},"The rules changed. Adapt your designs accordingly.",[21,2826,1726],{"id":1725},[1728,2828,2829,2834],{},[1731,2830,2831],{"v-slot:title":82},[17,2832,2833],{},"Apple Newsroom",[1731,2835,2836],{"v-slot:content":82},[17,2837,2838,2843],{},[484,2839,2842],{"href":2840,"rel":2841},"https:\u002F\u002Fwww.apple.com\u002Fnewsroom\u002F2025\u002F06\u002Fapple-introduces-a-delightful-and-elegant-new-software-design\u002F",[488],"apple.com"," — Liquid Glass announcement",[1728,2845,2846,2851],{},[1731,2847,2848],{"v-slot:title":82},[17,2849,2850],{},"WebKit Safari 26.0 Features",[1731,2852,2853],{"v-slot:content":82},[17,2854,2855,2860],{},[484,2856,2859],{"href":2857,"rel":2858},"https:\u002F\u002Fwebkit.org\u002Fblog\u002F17333\u002Fwebkit-features-in-safari-26-0\u002F",[488],"webkit.org"," — Safari 26 release notes",[1728,2862,2863,2868],{},[1731,2864,2865],{"v-slot:title":82},[17,2866,2867],{},"Ben Frain Analysis",[1731,2869,2870],{"v-slot:content":82},[17,2871,2872,2877],{},[484,2873,2876],{"href":2874,"rel":2875},"https:\u002F\u002Fbenfrain.com\u002Fios26-safari-theme-color-tab-tinting-with-fixed-position-elements\u002F",[488],"benfrain.com"," — Deep dive on theme-color removal",[1728,2879,2880,2885],{},[1731,2881,2882],{"v-slot:title":82},[17,2883,2884],{},"WebKit Bug #301756",[1731,2886,2887],{"v-slot:content":82},[17,2888,2889,2894],{},[484,2890,2893],{"href":2891,"rel":2892},"https:\u002F\u002Fbugs.webkit.org\u002Fshow_bug.cgi?format=multiple&id=301756",[488],"bugs.webkit.org"," — Fixed element color tinting issues",[1728,2896,2897,2902],{},[1731,2898,2899],{"v-slot:title":82},[17,2900,2901],{},"Apple Insider",[1731,2903,2904],{"v-slot:content":82},[17,2905,2906,2911],{},[484,2907,2910],{"href":2908,"rel":2909},"https:\u002F\u002Fappleinsider.com\u002Farticles\u002F25\u002F06\u002F18\u002Fhow-safari-in-ios-26-macos-26-puts-content-first-with-liquid-glass-ui-changes",[488],"appleinsider.com"," — Safari Liquid Glass UI analysis",[1728,2913,2914,2919],{},[1731,2915,2916],{"v-slot:title":82},[17,2917,2918],{},"Viewport Changes Guide",[1731,2920,2921],{"v-slot:content":82},[17,2922,2923,2928],{},[484,2924,2927],{"href":2925,"rel":2926},"https:\u002F\u002Fstripearmy.medium.com\u002Fios-26-0-be-prepared-for-viewport-changes-in-safari-e867d7eace43",[488],"medium.com"," — iOS 26 viewport behavior changes",[1873,2930,2931],{},"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 .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 .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":82,"searchDepth":134,"depth":134,"links":2933},[2934,2935,2940,2945,2950,2956,2957,2958,2959],{"id":1969,"depth":134,"text":1970},{"id":2048,"depth":134,"text":2049,"children":2936},[2937,2938,2939],{"id":2055,"depth":143,"text":2056},{"id":2071,"depth":143,"text":2072},{"id":2081,"depth":143,"text":2082},{"id":2093,"depth":134,"text":2094,"children":2941},[2942,2943,2944],{"id":2100,"depth":143,"text":2101},{"id":2182,"depth":143,"text":2183},{"id":2294,"depth":143,"text":2295},{"id":2308,"depth":134,"text":2309,"children":2946},[2947,2948,2949],{"id":2315,"depth":143,"text":2316},{"id":2395,"depth":143,"text":2396},{"id":2503,"depth":143,"text":2504},{"id":2516,"depth":134,"text":2517,"children":2951},[2952,2953,2954,2955],{"id":2520,"depth":143,"text":2521},{"id":2530,"depth":143,"text":2531},{"id":2638,"depth":143,"text":2639},{"id":2747,"depth":143,"text":2748},{"id":2757,"depth":134,"text":2758},{"id":2781,"depth":134,"text":2782},{"id":1689,"depth":134,"text":1690},{"id":1725,"depth":134,"text":1726},"Apple dropped theme-color meta tags. Understanding why Safari now derives toolbar colors from your CSS, and how Liquid Glass changed the rules.","iOS 26 Safari Toolbar Colors","iOS 26 Toolbar Colors",{},"\u002Fblog\u002Fios26-safari-toolbar-colors",{"title":1950,"description":2960},"blog\u002Fios26-safari-toolbar-colors",[2968,2969,2119,2970,2971],"ios","safari","apple","design","2WBmkxWrtklvdwOe77IL18gJ8joEJ8q2Q1BJhse8YKg",1782490001674]