{"slug": "bun-v1-3-10", "title": "Bun v1.3.10", "summary": "Based on the article, Bun version 1.3.10 introduces a completely rewritten REPL in Zig that starts instantly with features like syntax highlighting, persistent history, and top-level await support. The update also adds the ability to compile HTML files with `--compile --target=browser` for self-contained output, and now fully supports TC39 stage-3 standard ES decorators including the `accessor` keyword and decorator metadata.", "body_md": "#### To install Bun\n\n```\ncurl -fsSL https://bun.sh/install | bash\nnpm install -g bun\npowershell -c \"irm bun.sh/install.ps1|iex\"\nscoop install bun\nbrew tap oven-sh/bun\nbrew install bun\ndocker pull oven/bun\ndocker run --rm --init --ulimit memlock=-1:-1 oven/bun\n```\n\n#### To upgrade Bun\n\n```\nbun upgrade\n```\n\n[New REPL](#new-repl)\n\nBun's REPL has been completely rewritten in Zig, replacing the previous third-party npm package. The new REPL starts instantly without downloading any packages, and includes a full-featured terminal UI.\n\nIn the next version of Bun\n\n— Jarred Sumner (@jarredsumner)\n\nBun gets a native REPL[pic.twitter.com/RLtaUymgWu][February 25, 2026]\n\nFeatures:\n\n**Copy to clipboard**-`.copy`\n\ncommand copies the expression to clipboard**Top-level await**- you can use it.** ESM import & require**- all the ways to load modules just work.** Syntax highlighting**— JavaScript code is colorized as you type.** Line editing with Emacs keybindings**—`Ctrl+A/E`\n\nto jump to start/end of line,`Ctrl+K/U`\n\nto kill to end/start,`Ctrl+W`\n\nto delete word backward,`Ctrl+L`\n\nto clear screen, and arrow key navigation.**Persistent history**— Command history is saved to`~/.bun_repl_history`\n\nand navigable with Up/Down arrows or`Ctrl+P/N`\n\n.**Tab completion**— Complete object properties and REPL commands.** Multi-line input**— Automatic continuation detection for incomplete expressions.** REPL commands**—`.help`\n\n,`.exit`\n\n,`.clear`\n\n,`.load`\n\n,`.save`\n\n,`.editor`\n\n.**Special variables**—`_`\n\nholds the last expression result,`_error`\n\nholds the last error.**Proper REPL semantics**—`const`\n\nand`let`\n\ndeclarations are hoisted to`var`\n\nfor persistence across lines, top-level`await`\n\nworks out of the box,`import`\n\nstatements are converted to dynamic imports, and object literals like`{ a: 1 }`\n\nare detected without needing parentheses:\n\n``` js\n> const x = 42\n> x + 1\n43\n> await fetch(\"https://example.com\").then(r => r.status)\n200\n> import { readFile } from \"fs/promises\"\n> { name: \"bun\", version: Bun.version }\n{ name: \"bun\", version: \"1.3.1\" }\n```\n\n`--compile --target=browser`\n\nfor self-contained HTML output\n\n`--compile --target=browser`\n\nfor self-contained HTML outputYou can now use `bun build --compile --target=browser`\n\nto produce self-contained HTML files with all JavaScript, CSS, and assets inlined directly into the output. This supports TypeScript, JSX, React, CSS, ESM, CJS, and everything else Bun's bundler already supports.\n\nThis is useful for distributing `.html`\n\nfiles that work via `file://`\n\nURLs without needing a web server or worrying about CORS restrictions.\n\n`<script src=\"...\">`\n\ntags become inline`<script>`\n\nwith bundled code`<link rel=\"stylesheet\">`\n\ntags become inline`<style>`\n\ntags- Asset references (including CSS\n`url()`\n\n) become`data:`\n\nURIs\n\n**CLI:**\n\n```\nbun build --compile --target=browser ./index.html\n```\n\n**API:**\n\n```\nawait Bun.build({\n  entrypoints: [\"./index.html\"],\n  target: \"browser\",\n  compile: true,\n});\n```\n\nAll entrypoints must be `.html`\n\nfiles. Cannot be used with `--splitting`\n\n.\n\n[TC39 Standard ES Decorators](#tc39-standard-es-decorators)\n\nBun's transpiler now fully supports [TC39 stage-3 standard ES decorators](https://github.com/tc39/proposal-decorators) — the non-legacy variant used when `experimentalDecorators`\n\nis **not** enabled in your `tsconfig.json`\n\n.\n\nThis has been one of the most requested features since 2023. Previously, Bun only supported legacy/experimental TypeScript decorators, which meant code using the modern decorator spec — including the `accessor`\n\nkeyword, decorator metadata via `Symbol.metadata`\n\n, and the `ClassMethodDecoratorContext`\n\n/`ClassFieldDecoratorContext`\n\nAPIs — would either fail to parse or produce incorrect results.\n\nNow, all of the following work correctly:\n\n```\nfunction logged(originalMethod: any, context: ClassMethodDecoratorContext) {\n  const name = String(context.name);\n  return function (this: any, ...args: any[]) {\n    console.log(`Entering ${name}`);\n    const result = originalMethod.call(this, ...args);\n    console.log(`Exiting ${name}`);\n    return result;\n  };\n}\n\nclass Example {\n  @logged\n  greet(name: string) {\n    console.log(`Hello, ${name}!`);\n  }\n}\n\nnew Example().greet(\"world\");\n// Entering greet\n// Hello, world!\n// Exiting greet\n```\n\nAuto-accessors with the `accessor`\n\nkeyword are now supported, including on private fields:\n\n``` js\nimport { Signal } from \"signal-polyfill\";\n\nfunction signal(target: any) {\n  const { get } = target;\n  return {\n    get() {\n      return get.call(this).get();\n    },\n    set(value: any) {\n      get.call(this).set(value);\n    },\n    init(value: any) {\n      return new Signal.State(value);\n    },\n  };\n}\n\nclass Counter {\n  @signal accessor #value = 0;\n\n  get value() {\n    return this.#value;\n  }\n  increment() {\n    this.#value++;\n  }\n}\n\nconst c = new Counter();\nc.increment();\nconsole.log(c.value); // 1\n```\n\nField decorators with `addInitializer`\n\n, decorator metadata, and correct evaluation ordering all work as specified:\n\n```\nfunction wrap<This, T>(value: T, ctx: ClassFieldDecoratorContext<This, T>) {\n  ctx.addInitializer(function () {\n    console.log(\"Initialized\", this);\n  });\n  return (initialValue: T) => initialValue;\n}\n\nclass A {\n  @wrap\n  public a: number = 1;\n}\n\nconst a = new A(); // \"Initialized\" A {}\n```\n\n[What's supported](#what-s-supported)\n\n| Feature | Details |\n|---|---|\n| Method/getter/setter decorators | Static and instance, public and private |\n| Field decorators | Initializer replacement + `addInitializer` |\nAuto-accessor (`accessor` keyword) | Public and private fields |\n| Class decorators | Statement and expression positions |\n| Decorator metadata | `Symbol.metadata` support |\n| Evaluation order | Decorator expressions and computed keys evaluated in spec-defined order |\n\nLegacy decorators (`experimentalDecorators: true`\n\nin `tsconfig.json`\n\n) continue to work as before.\n\n[Faster event loop on macOS & Linux](#faster-event-loop-on-macos-linux)\n\nEnsuring everyone really understands.\n\n— Ben Dicken (@BenjDicken)[https://t.co/REGFQ2se1G][pic.twitter.com/jvoXgSVyYe][February 10, 2026]\n\n[Windows ARM64 Support](#windows-arm64-support)\n\nBun now natively supports Windows on ARM64 (Snapdragon, etc.). You can install and run Bun on ARM64 Windows devices, and cross-compile standalone executables targeting `bun-windows-arm64`\n\n.\n\n```\nawait Bun.build({\n  entrypoints: [\"./path/to/my/app.ts\"],\n  compile: {\n    target: \"bun-windows-arm64\",\n    outfile: \"./myapp\", // .exe added automatically\n  },\n});\n```\n\nOr from the CLI:\n\n```\nbun build --compile --target=bun-windows-arm64 ./path/to/my/app.ts --outfile myapp\n```\n\n[Barrel Import Optimization](#barrel-import-optimization)\n\nWhen you `import { Button } from 'antd'`\n\n, the bundler normally has to parse every file that `antd/index.js`\n\nre-exports — potentially thousands of modules. Bun's bundler now detects pure barrel files (re-export index files) and **only parses the submodules you actually use**.\n\nIn the next version of Bun\n\n— Jarred Sumner (@jarredsumner)\n\nBun's bundler & frontend dev server gets automatic barrel-file optimization.\n\nThis makes libraries like lucida-react build up to 2x faster[pic.twitter.com/LxS0Y4VjcI][February 12, 2026]\n\nThis works in two modes:\n\n**Automatic mode:** Packages with`\"sideEffects\": false`\n\nin their`package.json`\n\nget barrel optimization automatically — no configuration needed.**Explicit mode:** Use the new`optimizeImports`\n\noption in`Bun.build()`\n\nfor packages that don't have`\"sideEffects\": false`\n\n.\n\n```\nawait Bun.build({\n  entrypoints: [\"./app.ts\"],\n  optimizeImports: [\"antd\", \"@mui/material\", \"lodash-es\"],\n});\n```\n\nA file qualifies as a barrel if every named export is a re-export (`export { X } from './x'`\n\n). If a barrel file has any local exports, or if any importer uses `import *`\n\n, all submodules are loaded as usual.\n\n`export *`\n\nre-exports are always loaded to avoid circular resolution issues — only named re-exports that aren't used by any importer are deferred. Multi-level barrel chains (A re-exports from B re-exports from C) are handled automatically via BFS un-deferral.\n\n[Fewer closures in bundled output](#fewer-closures-in-bundled-output)\n\nTo make ESM & CJS work as people expect, all bundlers must generate additional wrapping code around modules. This wrapper code has some overhead. And in v1.3.10, Bun's bundled output for ESM & CJS projects now has significantly less overhead.\n\nMeasured on a ~23 MB single-bundle app with 600+ React imports:\n\n| Metric | Before | After | Delta |\n|---|---|---|---|\nTotal objects | 745,985 | 664,001 | −81,984 (−11%) |\nHeap size | 115 MB | 111 MB | −4 MB |\n| GetterSetter | 34,625 | 13,428 | −21,197 (−61%) |\n| Function | 221,302 | 197,024 | −24,278 (−11%) |\n| JSLexicalEnvironment | 70,101 | 44,633 | −25,468 (−36%) |\n\nThese improvements apply automatically to all `Bun.build()`\n\nand `bun build`\n\noutput — no code changes required.\n\n`--retry`\n\nflag for `bun test`\n\n`--retry`\n\nflag for `bun test`\n\nYou can now set a default retry count for all tests using the `--retry`\n\nflag. This is useful for handling flaky tests in CI environments without adding `{ retry: N }`\n\nto every individual test.\n\n```\n# Retry all failing tests up to 3 times\nbun test --retry 3\n```\n\nPer-test `{ retry: N }`\n\noptions still take precedence over the global flag:\n\n``` js\nimport { test, expect } from \"bun:test\";\n\n// Uses the global --retry count\ntest(\"flaky network call\", async () => {\n  const res = await fetch(\"https://example.com/api\");\n  expect(res.ok).toBe(true);\n});\n\n// Overrides the global --retry count\ntest(\"very flaky test\", { retry: 5 }, () => {\n  // ...\n});\n```\n\nYou can also configure this in `bunfig.toml`\n\n:\n\n```\n[test]\nretry = 3\n```\n\nWhen using the JUnit XML reporter, each retry attempt is now emitted as a separate `<testcase>`\n\nentry. Failed attempts include a `<failure>`\n\nelement, followed by the final passing `<testcase>`\n\n. This gives CI systems and flaky test detection tools per-attempt timing and result data using standard JUnit XML.\n\nThanks to @alii for the contribution!\n\n`ArrayBuffer`\n\noutput for `Bun.generateHeapSnapshot(\"v8\")`\n\n`ArrayBuffer`\n\noutput for `Bun.generateHeapSnapshot(\"v8\")`\n\n`Bun.generateHeapSnapshot(\"v8\")`\n\nnow accepts an optional second argument `\"arraybuffer\"`\n\nto return the heap snapshot as an `ArrayBuffer`\n\ninstead of a string. This avoids the overhead of creating a JavaScript string for large snapshots and prevents potential crashes when heap snapshots approach the max `uint32`\n\nstring length.\n\nThe `ArrayBuffer`\n\ncontains UTF-8 encoded JSON that can be written directly to a file or decoded with `TextDecoder`\n\n:\n\n``` js\nconst snapshot = Bun.generateHeapSnapshot(\"v8\", \"arraybuffer\");\n\n// Write directly to a file — no string conversion needed\nawait Bun.write(\"heap.heapsnapshot\", snapshot);\n\n// Or decode and parse if needed\nconst parsed = JSON.parse(new TextDecoder().decode(snapshot));\n```\n\n[TLS keepalive for custom SSL configs (mTLS)](#tls-keepalive-for-custom-ssl-configs-mtls)\n\nPreviously, all HTTP connections using custom TLS configurations — such as client certificates (mTLS) or custom CA certificates — had keepalive disabled, forcing a new TCP+TLS handshake on every request.\n\nCustom TLS connections now properly participate in keepalive pooling. Identical TLS configurations are deduplicated via a global registry with reference counting, and the SSL context cache uses bounded LRU eviction (max 60 entries, 30-minute TTL).\n\nThis is automatically enabled when using `fetch()`\n\nor `bun install`\n\n.\n\n[Updated Root Certificates](#updated-root-certificates)\n\nBun's bundled root certificates have been updated from NSS 3.117 to NSS 3.119 (Firefox 147.0.3). This removes 4 distrusted CommScope root certificates per Mozilla's NSS 3.118 changes:\n\n- CommScope Public Trust ECC Root-01\n- CommScope Public Trust ECC Root-02\n- CommScope Public Trust RSA Root-01\n- CommScope Public Trust RSA Root-02\n\nThis update resolves TLS connection failures that some users experienced after Cloudflare rotated `example.com`\n\n's certificate to a chain terminating at the removed `AAA Certificate Services`\n\n(Comodo) root CA.\n\n[Upgraded JavaScriptCore Engine](#upgraded-javascriptcore-engine)\n\nBun's underlying JavaScript engine (JavaScriptCore) has been upgraded, bringing several performance improvements and bug fixes.\n\n[Deep Rope String Slicing — 168x faster](#deep-rope-string-slicing-168x-faster)\n\nRepeated string concatenation using `+=`\n\npreviously created deeply nested rope strings that caused O(n²) behavior when slicing. The engine now limits rope traversal depth and falls back to flattening the string, dramatically improving performance.\n\n``` js\nlet s = \"\";\nfor (let i = 0; i < 100_000; i++) {\n  s += \"A\";\n}\n// Slicing this string is now up to 168x faster\ns.slice(0, 100);\n```\n\n`String.prototype.endsWith`\n\n— up to 10.5x faster\n\n`String.prototype.endsWith`\n\n— up to 10.5x faster`String.prototype.endsWith`\n\nis now optimized in the DFG/FTL JIT tiers with a dedicated intrinsic. Constant-foldable cases are up to 10.5x faster, and the general case is 1.45x faster.\n\n``` js\nconst str = \"hello world\";\nstr.endsWith(\"world\"); // up to 10.5x faster when constant-folded\n```\n\n[RegExp Flag Getters — 1.6x faster](#regexp-flag-getters-1-6x-faster)\n\nRegExp flag property getters (`.global`\n\n, `.ignoreCase`\n\n, `.multiline`\n\n, `.dotAll`\n\n, `.sticky`\n\n, `.unicode`\n\n, `.unicodeSets`\n\n, `.hasIndices`\n\n) now have inline cache and DFG/FTL support, making them ~1.6x faster.\n\n`Intl.formatToParts`\n\n— up to 1.15x faster\n\n`Intl.formatToParts`\n\n— up to 1.15x faster`Intl`\n\n`formatToParts`\n\nmethods now use pre-built structures for returned part objects, reducing allocation overhead.\n\n[Other Engine Improvements](#other-engine-improvements)\n\n`BigInt`\n\nvalues now store digits inline, eliminating a separate allocation and pointer indirection- String iterator creation is now optimized in DFG/FTL, enabling allocation sinking\n- Integer modulo operations in DFG/FTL now avoid expensive\n`fmod`\n\ndouble operations when inputs are integer-like - The JIT worklist thread count has been increased from 3 to 4\n- Register allocator improvements for better spill slot coalescing\n\n[Bug Fixes](#bug-fixes)\n\n- Fixed:\n`RegExp.prototype.test()`\n\nreturning incorrect results due to stale captures in FixedCount groups (@pchasco) - Fixed: Infinite loop in RegExp JIT when using non-greedy backreferences to zero-width captures (@pchasco)\n- Fixed: Incorrect RegExp backtracking from nested alternative end branches (@pchasco)\n- Fixed: WebAssembly\n`ref.cast`\n\n/`ref.test`\n\nproducing wrong results due to inverted condition in B3 optimization (@nickaein)\n\n`structuredClone`\n\nis up to 25x faster for arrays\n\n`structuredClone`\n\nis up to 25x faster for arrays`structuredClone`\n\nand `postMessage`\n\nnow have a fast path when the root value is a dense array of primitives or strings. Instead of going through the full serialization/deserialization machinery, Bun keeps data in native structures and uses `memcpy`\n\nwhere possible.\n\nThis optimization applies automatically when cloning arrays of numbers, strings, booleans, `null`\n\n, or `undefined`\n\n— the most common case for `postMessage`\n\npayloads and deep copies.\n\n``` js\nconst numbers = Array.from({ length: 1000 }, (_, i) => i);\nstructuredClone(numbers); // 25.3x faster\n\nconst strings = Array.from({ length: 100 }, (_, i) => `item-${i}`);\nstructuredClone(strings); // 2.2x faster\n\nconst mixed = [1, \"hello\", true, null, undefined, 3.14];\nstructuredClone(mixed); // 2.3x faster\n```\n\n| Benchmark | Before | After | Speedup |\n|---|---|---|---|\n`structuredClone([10 numbers])` | 308.71 ns | 40.38 ns | 7.6x |\n`structuredClone([100 numbers])` | 1.62 µs | 86.87 ns | 18.7x |\n`structuredClone([1000 numbers])` | 13.79 µs | 544.56 ns | 25.3x |\n`structuredClone([10 strings])` | 642.38 ns | 307.38 ns | 2.1x |\n`structuredClone([100 strings])` | 5.67 µs | 2.57 µs | 2.2x |\n`structuredClone([10 mixed])` | 446.32 ns | 198.35 ns | 2.3x |\n\nNon-eligible inputs (objects, nested arrays) are unchanged with no regression.\n\nThanks to @sosukesuzuki for the contribution!\n\n`structuredClone`\n\nis faster for arrays of objects\n\n`structuredClone`\n\nis faster for arrays of objects`structuredClone`\n\nand `postMessage`\n\nnow use a fast path when cloning dense arrays of simple objects, completely bypassing byte-buffer serialization. This is the most common real-world pattern — arrays of flat objects with primitive or string values.\n\n``` js\n// This is now 1.7x faster than before\nconst data = [\n  { name: \"Alice\", age: 30 },\n  { name: \"Bob\", age: 25 },\n];\n\nconst cloned = structuredClone(data);\n```\n\nWhen the array contains objects that share the same shape (same property names in the same order), a structure cache skips repeated property transitions during deserialization — making same-shape object arrays especially fast.\n\nThis builds on the existing fast paths for dense arrays of primitives and strings (up to 25x faster for integer arrays), extending the optimization to the object case.\n\n| Benchmark | Node.js v24.12 | Bun v1.3.8 | Bun v1.3.1 |\n|---|---|---|---|\n`[10 objects]` | 2.83 µs | 2.72 µs | 1.56 µs (1.7x faster) |\n`[100 objects]` | 24.51 µs | 25.98 µs | 14.11 µs (1.8x faster) |\n\nThe fast path falls back to normal serialization for objects with getters/setters, nested objects/arrays, non-enumerable properties, or elements like `Date`\n\n, `RegExp`\n\n, `Map`\n\n, `Set`\n\n, and `ArrayBuffer`\n\n.\n\nThanks to @sosukesuzuki for the contribution!\n\n[Faster ](#faster-structuredclone-for-numeric-arrays)`structuredClone`\n\nfor numeric arrays\n\n`structuredClone`\n\nfor numeric arraysEliminated a redundant zero-fill in the `structuredClone`\n\nfast path for `Int32`\n\nand `Double`\n\narrays. Previously, an internal buffer was zero-initialized and then immediately overwritten with the actual data. Now the buffer is constructed directly from the source data in a single copy.\n\nThanks to @sosukesuzuki for the contribution!\n\n`Buffer.slice()`\n\n/ `Buffer.subarray()`\n\nis ~1.8x faster\n\n`Buffer.slice()`\n\n/ `Buffer.subarray()`\n\nis ~1.8x faster`Buffer.slice()`\n\nand `Buffer.subarray()`\n\nhave been moved from a JS builtin to a native C++ implementation, eliminating closure allocations and JS→C++ constructor overhead on every call. An int32 fast path skips `toNumber()`\n\ncoercion when arguments are already integers — the common case for calls like `buf.slice(0, 10)`\n\n.\n\n| Benchmark | Before | After | Speedup |\n|---|---|---|---|\n`Buffer(64).slice()` | 27.19 ns | 14.56 ns | 1.87× |\n`Buffer(1024).slice()` | 27.84 ns | 14.62 ns | 1.90× |\n`Buffer(1M).slice()` | 29.20 ns | 14.89 ns | 1.96× |\n`Buffer(64).slice(10)` | 30.26 ns | 16.01 ns | 1.89× |\n`Buffer(1024).slice(10, 100)` | 30.92 ns | 18.32 ns | 1.69× |\n`Buffer(1024).slice(-100, -10)` | 28.82 ns | 17.37 ns | 1.66× |\n`Buffer(1024).subarray(10, 100)` | 28.67 ns | 16.32 ns | 1.76× |\n\nThanks to @sosukesuzuki for the contribution!\n\n`path.parse()`\n\nis 2.2–7x faster\n\n`path.parse()`\n\nis 2.2–7x faster`path.parse()`\n\nnow uses a pre-built object structure for its return value, avoiding repeated property transitions on every call. This brings **~2.2–2.8x** speedups for typical paths and up to **~7x** for edge cases like empty strings.\n\n``` js\nimport { posix } from \"path\";\n\n// 2.2x faster (119ns vs 267ns)\nposix.parse(\"/home/user/dir/file.txt\");\n// => { root: \"/\", dir: \"/home/user/dir\", base: \"file.txt\", ext: \".txt\", name: \"file\" }\n\n// 7x faster (21ns vs 152ns)\nposix.parse(\"\");\n// => { root: \"\", dir: \"\", base: \"\", ext: \"\", name: \"\" }\n```\n\n| Path | Before | After | Speedup |\n|---|---|---|---|\n`\"/home/user/dir/file.txt\"` | 266.71 ns | 119.62 ns | 2.23x |\n`\"/home/user/dir/\"` | 239.10 ns | 91.46 ns | 2.61x |\n`\"file.txt\"` | 232.55 ns | 89.20 ns | 2.61x |\n`\"/root\"` | 246.75 ns | 92.68 ns | 2.66x |\n`\"\"` | 152.19 ns | 20.72 ns | 7.34x |\n\nThanks to @sosukesuzuki for the contribution!\n\n[Fixed: ](#fixed-bun-spawn-stdio-pipes-breaking-python-asyncio-based-mcp-servers)`Bun.spawn()`\n\nstdio pipes breaking Python asyncio-based MCP servers\n\n`Bun.spawn()`\n\nstdio pipes breaking Python asyncio-based MCP serversBun's subprocess stdio pipes used `shutdown()`\n\ncalls on their underlying socketpairs to make them unidirectional. On `SOCK_STREAM`\n\nsockets, `shutdown(SHUT_WR)`\n\nsends a FIN to the peer — which caused programs that poll their stdio file descriptors for readability (like Python's `asyncio.connect_write_pipe()`\n\n) to interpret it as \"connection closed\" and tear down their transport prematurely.\n\nThis broke **all Python MCP servers** using the `model_context_protocol`\n\nSDK whenever they took more than a few seconds to initialize. The `shutdown()`\n\ncalls have been removed entirely — the socketpairs are already used unidirectionally by convention, and the calls provided no functional benefit.\n\n``` js\n// Python MCP servers spawned via Bun.spawn() now work correctly\nconst proc = Bun.spawn({\n  cmd: [\"python3\", \"mcp_server.py\"],\n  stdin: \"pipe\",\n  stdout: \"pipe\",\n  stderr: \"pipe\",\n});\n\n// Previously, the Python server's asyncio write transport would\n// be torn down after a few seconds of initialization delay.\n// Now it stays open as expected.\nconst response = await new Response(proc.stdout).text();\n```\n\n[Bugfixes](#bugfixes)\n\n[Node.js compatibility improvements](#node-js-compatibility-improvements)\n\n- Fixed:\n`AsyncLocalStorage`\n\ncontext not being preserved in`stream.finished`\n\ncallbacks, causing`getStore()`\n\nto return`undefined`\n\ninstead of the expected value - Fixed:\n`Error.captureStackTrace(e, fn)`\n\nwith a function not in the call stack now correctly returns the error name and message (e.g.`\"Error: test\"`\n\n) instead of`undefined`\n\n, matching Node.js behavior - Fixed:\n`fs.watch`\n\nand`fs.watchFile`\n\nnot properly handling`file:`\n\nURL strings with percent-encoded characters (e.g.`%20`\n\nfor spaces) - Fixed:\n`node:http`\n\nsending duplicate`Transfer-Encoding: chunked`\n\nheaders when explicitly set via`res.writeHead()`\n\n, which caused nginx 1.25+ to return 502 errors (@psmamps) - Fixed:\n`http.ClientRequest.write()`\n\ncalled multiple times was stripping the explicitly-set`Content-Length`\n\nheader and switching to`Transfer-Encoding: chunked`\n\n, breaking binary file uploads (e.g. Vercel CLI). Bun now preserves`Content-Length`\n\nwhen explicitly set, matching Node.js behavior. - Fixed:\n`OutgoingMessage.setHeaders()`\n\nincorrectly throwing`ERR_HTTP_HEADERS_SENT`\n\n- Fixed: HTTP response splitting vulnerability in\n`node:http`\n\n. Thanks to @VenkatKwest for reporting this! - Fixed: Crash when accessing\n`X509Certificate.issuerCertificate`\n\n- Fixed: Rare crash in\n`napi_close_callback_scope`\n\n- Fixed: ref count leak in\n`setImmediate`\n\nwhen the timer's JS object was garbage collected before the immediate task ran - Fixed: dynamic\n`import()`\n\nof unknown`node:`\n\nmodules (like`node:sqlite`\n\n) inside CJS files no longer fails at transpile time, allowing try/catch to handle the error gracefully at runtime. This fixes Next.js builds with turbopack +`cacheComponents: true`\n\n+ Better Auth, where Kysely's dialect detection uses`import(\"node:sqlite\")`\n\ninside a try/catch. - Fixed: three GC safety issues that could cause crashes during garbage collection marking, most notably affecting projects using\n`module._compile`\n\noverrides (`ts-node`\n\n,`pirates`\n\n,`@swc-node/register`\n\n, etc.) where an unvisited write barrier could lead to use-after-free crashes - Fixed: potential GC-related crashes when constructing objects with string values (e.g., HTTP headers, SQLite column names) by avoiding GC allocations inside\n`ObjectInitializationScope`\n\n(thanks @sosukesuzuki!) - Fixed: crash on older Linux kernels (< 3.17, e.g. Synology NAS) where the\n`getrandom()`\n\nsyscall doesn't exist, causing a panic with`\"getrandom() failed to provide entropy\"`\n\n. Bun now falls back to`/dev/urandom`\n\nvia BoringSSL on these systems. - Fixed: Socket\n`recvfrom`\n\nfailing with`EINVAL`\n\non gVisor-based environments (e.g. Google Cloud Run) due to invalid`MSG_NOSIGNAL`\n\nflag being passed to receive operations - Fixed: a crash on Windows (\n`OutOfMemory`\n\npanic) in`node:fs`\n\npath handling when the system is under memory pressure by removing an unnecessary 64KB buffer allocation for paths with drive letter - Fixed: memory leak when upgrading TCP sockets to TLS in node:tls (thanks to @alanstott!)\n\n[Bun APIs](#bun-apis)\n\n- Fixed: Fuzzer-detected crash when using\n`Bun.spawn`\n\nwith`stdin: new Response(data)`\n\nconcurrently with`Bun.file().exists()`\n\ncalls and other spawned process stdout reads - Fixed: Fuzzer-detected crash in\n`Bun.spawn`\n\n/`Bun.spawnSync`\n\ncaused by integer overflow when the command array has a spoofed`.length`\n\nnear`u32`\n\nmax - Fixed: Fuzzer-detected crash caused by a double-free in\n`Bun.plugin.clearAll()`\n\nthat could corrupt the heap allocator during Worker termination or VM destruction - Fixed: Fuzzer-detected crash when calling\n`Listener.getsockname()`\n\nwithout an object argument or with a non-object argument (e.g.`undefined`\n\n,`123`\n\n,`\"foo\"`\n\n) due to a null pointer dereference - Fixed:\n`Bun.stripANSI()`\n\nhanging indefinitely in certain cases - Fixed: crash when resolving\n`bun:main`\n\nbefore the entry point is generated, such as in HTML entry points or the test runner - Fixed:\n`db.close(true)`\n\nthrowing \"database is locked\" after using`db.transaction()`\n\ndue to transaction controller prepared statements not being finalized on close - Fixed:\n`bun:sql`\n\nPostgreSQL client now uses constant-time comparison for SCRAM-SHA-256 server signature verification, preventing potential timing side-channel attacks - Fixed: HTTP header injection vulnerability in S3 client where CRLF characters in\n`contentDisposition`\n\n,`contentEncoding`\n\n, or`type`\n\noptions could be used to inject arbitrary HTTP headers - Fixed: Memory leak (~260KB per request) when cancelling streaming HTTP response bodies via\n`reader.cancel()`\n\nor`body.cancel()`\n\n. A strong GC root on the`ReadableStream`\n\nwas never released on cancellation, causing`ReadableStream`\n\nobjects, associated`Promise`\n\ns, and`Uint8Array`\n\nbuffers to be retained indefinitely. (thanks @sosukesuzuki!) - Fixed: Memory leak when cancelling S3 download streams mid-download —\n`ReadableStream`\n\nobjects were retained indefinitely because the strong GC reference wasn't released on cancel - Fixed:\n`Bun.build()`\n\nfailing with`NotOpenForReading`\n\nwhen called multiple times after using`FileSystemRouter`\n\nroutes as entrypoints. The`FileSystemRouter`\n\nwas caching file descriptors that`Bun.build()`\n\nwould later close, causing subsequent builds to fail with stale file descriptors. (@ecd4e680) - Fixed: Crash when constructing objects from entries (e.g.\n`FileSystemRouter.routes`\n\n) caused by GC triggering during partially-initialized object slots - Fixed: \"Unknown HMR script\" error that occurred during rapid consecutive file edits when using Bun's dev server with HMR (@prekucki)\n- Fixed: Bun.sql now rejects null bytes in connection parameters to prevent protocol injection\n\n[Web APIs](#web-apis)\n\n- Fixed: WebSocket connections over\n`wss://`\n\nthrough an HTTP proxy crashing or receiving spurious 1006 close codes instead of clean 1000 closes when the server sent a ping frame - Fixed: WebSocket client frame desync when pong payloads were split across TCP segments, which could cause subsequent messages to be misinterpreted as invalid frame headers\n- Fixed: Missing RFC 6455 validation for WebSocket pong control frames — payloads exceeding 125 bytes are now correctly rejected, matching the existing behavior for ping and close frames\n\n[bun install](#bun-install)\n\n- Fixed:\n`bun install`\n\nproducing incomplete`node_modules`\n\non NFS, FUSE, and bind mount filesystems where directory entries were silently skipped due to unknown file types - Fixed: Path traversal vulnerability in tarball directory extraction.\n- Fixed: Scanner-detected undefined behavior in the .npmrc parser when processing truncated or invalid UTF-8 sequences in\n`.npmrc`\n\nfiles - Improved: Bun now generates & verifies integrity hashes for GitHub & HTTPS tarball dependencies. Thanks to @dsherret and @orenyomtov for reporting this issue!\n\n[JavaScript bundler](#javascript-bundler)\n\n- Fixed:\n`bun build --compile`\n\non Linux could produce a corrupted binary when a partial write occurred during executable generation - Fixed:\n`bun build --compile`\n\nproducing an all-zeros binary when the output directory is on a different filesystem than the temp directory, common in Docker containers, Gitea runners, and other environments using overlayfs - Fixed:\n`bun build --compile --sourcemap=external`\n\nnot writing`.map`\n\nfiles to disk — they were embedded in the executable but never actually written. With`--splitting`\n\n, each chunk now correctly gets its own`.map`\n\nfile instead of all overwriting a single file. (@AidanGoldworthy) - Fixed:\n`bun build`\n\nproducing syntactically invalid JavaScript (`Promise.resolve().then(() => )`\n\n) for unused dynamic imports like`void import(\"./dep.ts\")`\n\nor bare`import(\"./dep.ts\")`\n\nexpression statements - Fixed:\n`Bun.build`\n\nwith HTML entrypoints returning 404s for non-JS/CSS URL assets like`<link rel=\"manifest\" href=\"./manifest.json\" />`\n\n— these files are now correctly copied to the output directory instead of being parsed by their extension-based loader - Fixed: CSS\n`<link>`\n\ntags missing from second (and subsequent) HTML entrypoints when multiple HTML entrypoints shared the same CSS file with`--production`\n\nmode bundling\n\n[CSS Parser](#css-parser)\n\n- Fixed: CSS bundler leaving duplicate\n`@layer`\n\ndeclarations and`@import`\n\nstatements in output when using`@layer`\n\ndeclarations (e.g.`@layer one;`\n\n) followed by`@import`\n\nrules with`layer()`\n\n- Fixed: CSS bundler incorrectly removing\n`:root`\n\nrules when they appeared before`@property`\n\nat-rules due to style rule deduplication merging across at-rule boundaries (thanks @dylan-conway!)\n\n[bun test](#bun-test)\n\n- Fixed:\n`bun test --bail`\n\nnot writing JUnit reporter output file (`--reporter-outfile`\n\n) when early exit was triggered by a test failure\n\n[Bun Shell](#bun-shell)\n\n- Fixed:\n`seq inf`\n\n,`seq nan`\n\n, and`seq -inf`\n\nhanging indefinitely in Bun's shell instead of returning an error (thanks @dylan-conway!) - Fixed:\n`[[ -d \"\" ]]`\n\nand`[[ -f \"\" ]]`\n\ncrashing with an out-of-bounds panic in Bun's shell instead of returning exit code 1 (thanks @dylan-conway!) - Fixed: Scanner-detected crash when shell builtins (\n`ls`\n\n,`touch`\n\n,`mkdir`\n\n,`cp`\n\n) run inside command substitution`$(...)`\n\nand encounter errors (e.g., permission denied) (thanks @dylan-conway!) - Fixed: Bun's built-in\n`echo`\n\nin the shell treated`-e`\n\nand`-E`\n\nflags as literal text instead of parsing them, causing commands like`echo -e $password | sudo -S ...`\n\nto fail. Now supports`-e`\n\n(enable backslash escapes),`-E`\n\n(disable backslash escapes), and combined flags like`-ne`\n\n/`-en`\n\n, matching bash behavior. Supported escape sequences include`\\\\`\n\n,`\\a`\n\n,`\\b`\n\n,`\\c`\n\n,`\\e`\n\n,`\\f`\n\n,\n\n,`\\r`\n\n,`\\t`\n\n,`\\v`\n\n,`\\0nnn`\n\n(octal), and`\\xHH`\n\n(hex) - Fixed:\n`Bun.$`\n\nshell template literals leaking internal`__bunstr_N`\n\nreferences in output when an interpolated value contained a space and a subsequent value contained multi-byte UTF-8 characters (e.g.,`Í`\n\n,`€`\n\n) - Fixed: Scanner-detected crash in the\n`seq`\n\nshell builtin when called with only flags and no numeric arguments (e.g.`await Bun.$\\`\n\nseq -w``) - Fixed: crash in the shell interpreter when\n`setupIOBeforeRun`\n\nfails (e.g., stdout handle unavailable on Windows), which caused a segfault during GC sweep\n\n[TypeScript types](#typescript-types)\n\n- Fixed: TypeScript types for\n`Bun.build()`\n\nnow correctly allow`splitting`\n\nto be used together with`compile`\n\n(@alii)\n\n[Windows](#windows)\n\n- Fixed: Crash that could occur when spawning processes or writing to pipes in long-lived applications\n- Fixed: Crash on Windows when a standalone executable with\n`compile.autoloadDotenv = false`\n\nspawned a`Worker`\n\nin a directory containing a`.env`\n\nfile. The dotenv loader was mutating environment state owned by another thread, causing a`ThreadLock`\n\nassertion panic. (Thanks to @Hona!) - Fixed:\n`\"switch on corrupt value\"`\n\npanic on Windows impacting Claude Code & Opencode users - Fixed: Hypothetical crash on Windows when\n`GetFinalPathNameByHandleW`\n\nreturned paths exceeding buffer capacity", "url": "https://wpnews.pro/news/bun-v1-3-10", "canonical_source": "https://bun.com/blog/bun-v1.3.10", "published_at": "2026-02-26 06:31:59+00:00", "updated_at": "2026-05-22 20:40:31.311842+00:00", "lang": "en", "topics": ["developer-tools", "open-source"], "entities": ["Bun", "Jarred Sumner"], "alternates": {"html": "https://wpnews.pro/news/bun-v1-3-10", "markdown": "https://wpnews.pro/news/bun-v1-3-10.md", "text": "https://wpnews.pro/news/bun-v1-3-10.txt", "jsonld": "https://wpnews.pro/news/bun-v1-3-10.jsonld"}}