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