{"slug": "bun-v1-3-2", "title": "Bun v1.3.2", "summary": "Bun version 1.3.2 fixes 287 issues and restores hoisted installs as the default for existing workspaces, while keeping isolated installs as the default for new projects. The update introduces a lockfile `configVersion` to stabilize install defaults and prevent breaking changes during upgrades, and adds CPU profiling support via the `--cpu-prof` flag. Additionally, `bun install` is now faster for projects using popular libraries like esbuild and sharp, and the `bun:test` framework includes a new `onTestFinished` hook.", "body_md": "This release fixes 287 issues (addressing 324 👍).\n\n#### 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[Hoisted installs restored as default](#hoisted-installs-restored-as-default)\n\nIn Bun 1.3.0, we made isolated installs the default for workspaces. While this eliminated phantom dependencies and made installs faster and more predictable, it also introduced some issues for existing monorepos that relied on shared dependencies.\n\nIn Bun 1.3.2, Isolated installs are now only the default for *new* projects, while existing workspaces keep using hoisted installs unless explicitly configured.\n\n**To keep using isolated installs in your existing workspaces/monorepos**:\n\n```\n[install]\n# Explicitly set the linker to isolated\nlinker = \"isolated\"\n```\n\nOr use the `--linker=isolated`\n\nflag:\n\n```\nbun install --linker=isolated\n```\n\n**New projects using workspaces (or those without a lockfile)** continue to use isolated installs as the default.\n\n`configVersion` | Using workspaces? | Default Linker |\n|---|---|---|\n`1` | ✅ | `isolated` |\n`1` | ❌ | `hoisted` |\n`0` | ✅ | `hoisted` |\n`0` | ❌ | `hoisted` |\n\n[Lockfile ](#lockfile-configversion-stabilizes-install-defaults)`configVersion`\n\nstabilizes install defaults\n\n`configVersion`\n\nstabilizes install defaultsFlip-flopping between `isolated`\n\nand `hoisted`\n\nlinker is not good for our users. Collectively, breaking changes are a waste of everyone's time.\n\nTo make future bun upgrades easier, `bun install`\n\nnow writes a `configVersion`\n\nto `bun.lock`\n\n/ `bun.lockb`\n\n. This lets us change default configuration in the future without impacting existing projects.\n\nHere's how it works:\n\n**New projects**: Default to`configVersion = 1`\n\n(v1). In workspaces, v1 uses the isolated linker by default; otherwise it uses hoisted linking.**Existing Bun projects**: If your existing lockfile doesn't have a version yet, Bun sets`configVersion = 0`\n\n(v0) when you run`bun install`\n\n, preserving the previous hoisted linker default.**Migrations from other package managers**:- From pnpm:\n`configVersion = 1`\n\n(v1) - From npm or yarn:\n`configVersion = 0`\n\n(v0)\n\n- From pnpm:\n\n```\n// New projects:\n\"configVersion\": 1,\n\n// Existing projects without a version (after running `bun install`):\n\"configVersion\": 0,\n```\n\n[Faster ](#faster-bun-install)`bun install`\n\n`bun install`\n\nProjects that depend on popular libraries like `esbuild`\n\nor `sharp`\n\ninstall faster.\n\nIn the next version of Bun\n\n— Jarred Sumner (@jarredsumner)\n\nbun install gets smarter about choosing which & when postinstall scripts run.\n\nIn a repo with next.js & vite, bun install gets 6x faster.[pic.twitter.com/tJfJUD0pF9][November 1, 2025]\n\nTo disable Bun's built-in defaults via environment variables:\n\n```\nBUN_FEATURE_FLAG_DISABLE_NATIVE_DEPENDENCY_LINKER=1  # disables native binlinking\nBUN_FEATURE_FLAG_DISABLE_IGNORE_SCRIPTS=1            # disables script skipping\n```\n\n[CPU profiling with ](#cpu-profiling-with-cpu-prof)`--cpu-prof`\n\n`--cpu-prof`\n\nBun now supports CPU profiling for any script using the `--cpu-prof`\n\nflag. This records detailed information about how much time your program spends in each function, helping you identify performance bottlenecks and optimize hot paths.\n\nIn the next version of Bun\n\n— Jarred Sumner (@jarredsumner)\n\nbun --cpu-prof <script> generates CPU profiles you can open in Chrome DevTools, powered by JavaScriptCore's sampling profiler.[pic.twitter.com/cEPVDfw40S][October 30, 2025]\n\nProfiles are saved in the Chrome DevTools–compatible `.cpuprofile`\n\nformat and can be opened directly in Chrome DevTools (Performance tab) or VS Code's CPU profiler. Sampling runs at 1ms for fine-grained insights.\n\n| Flag | Description |\n|---|---|\n`--cpu-prof` | enables profiling |\n`--cpu-prof-name <filename>` | sets the output filename |\n`--cpu-prof-dir <dir>` | sets the output directory |\n\n```\n// script.js\nfunction fib(n) {\n  return n < 2 ? n : fib(n - 1) + fib(n - 2);\n}\n\nconsole.log(fib(35)); // some CPU work\n```\n\nYou can run this script with CPU profiling enabled:\n\n```\nbun --cpu-prof script.js\nbun --cpu-prof --cpu-prof-name my-profile.cpuprofile script.js\nbun --cpu-prof --cpu-prof-dir ./profiles script.js\n```\n\nOpen the generated `.cpuprofile`\n\nin Chrome DevTools → Performance → Load profile\n\n[bun:test onTestFinished hook](#bun-test-ontestfinished-hook)\n\n`bun:test`\n\nnow includes a new `onTestFinished(fn)`\n\nhook that runs at the very end of a test, after all `afterEach`\n\nhooks have completed. Use it for cleanup or assertions that must happen *after* every other per-test hook.\n\n- Runs only inside a test (not in\n`describe`\n\nor preload) - Supports async and done-style callbacks\n- Not supported in concurrent tests; use\n`test.serial`\n\ninstead or remove`test.concurrent`\n\n``` js\nimport { test, afterEach, onTestFinished, expect } from \"bun:test\";\n\ntest(\"runs after afterEach\", () => {\n  const calls = [];\n\n  afterEach(() => {\n    calls.push(\"afterEach\");\n  });\n\n   onTestFinished(() => {\n     calls.push(\"onTestFinished\");\n     // afterEach has already run\n     expect(calls).toEqual([\"afterEach\", \"onTestFinished\"]);\n  });\n\n  // test body...\n});\n\ntest.serial(\"async cleanup at the very end\", async () => {\n   onTestFinished(async () => {\n     await new Promise((r) => setTimeout(r, 10));\n     // ...close DB connections, stop servers, etc.\n   });\n\n  // test body...\n});\n```\n\nThanks to @pfg for the contribution!\n\n`ServerWebSocket`\n\nsubscriptions getter\n\n`ServerWebSocket`\n\nsubscriptions getter`ServerWebSocket`\n\nnow includes a `subscriptions`\n\ngetter that returns a de-duplicated list of topics the connection is currently subscribed to.\n\nThis makes it easy to inspect and manage per-connection state in pub/sub systems, for example, debugging topic subscriptions or cleaning up resources when clients disconnect.\n\nWhen a socket closes, `subscriptions`\n\nautomatically returns an empty array.\n\n``` js\nconst server = Bun.serve({\n  fetch(req, server) {\n    if (server.upgrade(req)) return;\n    return new Response(\"Not a websocket\");\n  },\n  websocket: {\n    open(ws) {\n      ws.subscribe(\"chat\");\n      ws.subscribe(\"notifications\");\n       console.log(ws.subscriptions); // [\"chat\", \"notifications\"]\n\n      ws.unsubscribe(\"chat\");\n       console.log(ws.subscriptions); // [\"notifications\"]\n    },\n    close(ws) {\n       console.log(ws.subscriptions); // []\n    },\n  },\n});\n```\n\nThis makes working with Bun's WebSocket pub/sub model more transparent and easier to debug.\n\n[Alpine 3.22 in official Docker images](#alpine-3-22-in-official-docker-images)\n\nBun's official Alpine Linux Docker images now use **Alpine 3.22** for both `x64`\n\nand `arm64(musl)`\n\nbuilds. This update brings the latest security patches, improved package compatibility, and a smaller base footprint.\n\n[Improved Git dependency resolution](#improved-git-dependency-resolution)\n\n`bun install`\n\nnow has better support for npm-style hosted Git URLs and GitHub shorthands.\n\nGitHub repositories specified with custom protocol prefixes are correctly identified and routed through the fast HTTP tarball pathway.\n\n```\n{\n  \"dependencies\": {\n    // GitHub shorthand (now parsed correctly and downloaded via HTTP tarball)\n    \"cool-lib\": \"github:owner/repo#v1.2.3\",\n\n    // Different protocols resolve deterministically\n    \"tooling-ssh\": \"git+ssh://git@github.com/owner/repo.git#main\",\n    \"tooling-https\": \"git+https://github.com/owner/repo.git#main\"\n  }\n}\n```\n\nThanks to @markovejnovic for the contribution!\n\n`bun list`\n\nalias for `bun pm ls`\n\n`bun list`\n\nalias for `bun pm ls`\n\nYou can now list your dependency tree with a shorter, top-level command: `bun list`\n\n. This is a direct alias for `bun pm ls`\n\nand supports the same flags (e.g. `--all`\n\n).\n\nIt supports all the same flags—including `--all`\n\nfor a full transitive view, making dependency inspection quicker and easier.\n\n```\n# List dependencies from the current lockfile (alias for `bun pm ls`)\nbun list\n# Show the full transitive dependency tree\nbun list --all\n```\n\n[spawnSync now runs on an isolated event loop](#spawnsync-now-runs-on-an-isolated-event-loop)\n\n`Bun.spawnSync`\n\n& `child_process.spawnSync`\n\nnow run on an isolated event loop from the rest of the process, preventing JavaScript timers and microtasks from firing and interfering with the main process's stdin/stdout. This aligns Bun's spawnSync behavior with Node.js and makes timeouts reliable across platforms, including Windows.\n\nThis is how it should've been done in the first place. There were several bugs and stability issues with the previous implementation, including cases where using `execSync`\n\nwith `vim`\n\nwould \"eat\" the first character of keypresses, making it feel very slow to do anything at all.\n\nIn rare cases, projects could mistakenly be depending on this behavior. Please let us know if you are negatively impacted by this change.\n\n[More bug fixes](#more-bug-fixes)\n\n[Node.js compatibility improvements](#node-js-compatibility-improvements)\n\n- Fixed:\n`EventEmitter`\n\ncould throw an error when`removeAllListeners(type)`\n\nwas called from within an event handler while a`removeListener`\n\nmeta-listener was registered and the target event had no listeners; behavior now matches Node.js (no error). - Fixed:\n`ServerResponse.prototype.writableNeedDrain`\n\nincorrectly returned true when the response had no handle, causing`fs.createReadStream().pipe(res)`\n\nand other piped streams to pause indefinitely in middleware/connect-to-web scenarios (e.g., Vite staticfile serving). Behavior now matches Node.js, allowing streams to flow and readable/end events to fire as expected. - Fixed:\n`process.mainModule`\n\nsetter/getter semantics now match Node.js - Fixed: Crash when user code overrides\n`process.nextTick`\n\n. Bun now safely uses the overridden function during internal scheduling (e.g., WebSocket internals) instead of crashing. - Fixed:\n`Buffer.isEncoding('')`\n\nincorrectly returned`true`\n\n; it now returns`false`\n\nto match Node.js behavior. - Fixed:\n`Module._resolveFilename`\n\nnow forwards the options object (including`options.paths`\n\n) to overridden implementations and honors`options.paths`\n\nwhen provided. This restores compatibility with Node-style require hooks (e.g., Next.js 16) and fixes Next.js 16 + React Compiler + Turbopack builds that previously failed with \"Cannot find module './node_modules/babel-plugin-react-compiler'\". - Fixed:\n`Module._resolveFilename`\n\nvalidates that`options.paths`\n\nis an array and throws`ERR_INVALID_ARG_TYPE`\n\notherwise, aligning with Node.js. - Fixed:\n`process.dlopen`\n\ncrashed when passed non-object exports (null, undefined, or primitives). Bun now matches Node.js ToObject semantics—throwing TypeError for null/undefined and boxing primitives—preventing segfaults when loading native addons.\n\n[N-API and native addons](#n-api-and-native-addons)\n\n- Fixed: N-API\n`napi_create_external_buffer`\n\nnow correctly handles empty inputs (null data and/or length 0) without throwing or creating a detached buffer. When length is 0, it returns a detached ArrayBuffer matching Node.js behavior.`napi_get_buffer_info`\n\nand`napi_get_arraybuffer_info`\n\ncorrectly report a null pointer and 0 length, and`napi_is_detached_arraybuffer`\n\nreturns true. This prevents`napi_create_reference`\n\ncrashes in addons (e.g. ref-napi, ffi-napi, @tdengine/client) and ensures zero-length buffers are created with safe finalization. - Fixed: Crash in N-API when ThreadSafeFunction finalizers or async work deinitialized the environment during dispatch, causing intermittent crashes. Environment references are now safely retained until operations complete, improving reliability for addons using ThreadSafeFunction and finalizers.\n- Fixed: N-API property access now returns undefined for missing properties and out-of-bounds elements (e.g.,\n`napi_get_property`\n\nand element getters), matching Node.js behavior. - Fixed: Numeric-string keys (e.g., \"0\", \"42\") are handled consistently as index access across N-API property operations (get/has/has_own/delete), aligning semantics with Node.js.\n- Fixed:\n`napi_delete_property`\n\n,`napi_has_property`\n\n, and`napi_has_own_property`\n\nnow return correct boolean results and propagate exceptions consistently, improving addon compatibility and correctness. - Fixed: Improved error handling across N-API property and element access to avoid spurious failures and improve reliability in native addons.\n- Fixed: Importing\n`better-sqlite3`\n\nnow fails fast with a clear, actionable error instead of crashing with a dlopen/symbol lookup error (`undefined symbol: node_module_register`\n\n). The message links to the tracking issue and suggests`bun:sqlite`\n\nas an alternative.\n\n[HTTP/HTTPS and networking](#http-https-and-networking)\n\n- Fixed: Restored use of the system CA trust store for TLS verification, resolving a 1.3.0 regression that caused some HTTPS requests to fail with\n`UNABLE_TO_GET_ISSUER_CERT_LOCALLY`\n\n. Bun now again loads default OS CA paths - Fixed: HTTP server could incorrectly mark a connection as idle after a write failure, leading to a request taking longer to timeout than expected.\n- Fixed: Upgrading WebSocket connections via\n`ws`\n\nmodule in certain cases could consume 100% CPU when it should be idling.\n\n[Fetch API](#fetch-api)\n\n- Fixed: Fetch API methods now reject with\n`TypeError`\n\ninstead of`Error`\n\nwhen the body has already been consumed (e.g., calling`text()`\n\nthen`json()`\n\non the same Request/Response), aligning with the Fetch spec and matching Node/Deno behavior.\n\n[bun test bugfixes](#bun-test-bugfixes)\n\n- Fixed:\n`bun:test`\n\nlifecycle hooks (`beforeAll`\n\n,`beforeEach`\n\n,`afterAll`\n\n,`afterEach`\n\n) no longer throw when called with a callback and options as the second argument.`(callback, options)`\n\nis now correctly parsed, supporting both object and numeric timeouts (e.g., fixes \"beforeAll() expects a function as the second argument\"). - Fixed:\n`bun:test`\n\nnow emits clearer errors when snapshot creation is attempted in CI. Messages explicitly refer to creation (not updating), include the received value, and (for file snapshots) the snapshot name, with guidance to use`--update-snapshots`\n\nor set`CI=false`\n\nto override. - Fixed: In rare cases,\n`bun test`\n\ncould crash when a test prompted for a sudo password or left a dangling process - Fixed:\n`expect(...).toThrow`\n\nwith an async function no longer crashes the test runner when the rejection occurs after the test timeout. The test now times out and reports a failure as expected. - Fixed: bun-types for bun:test incorrectly typed\n`vi.mock(...)`\n\nas`vi.module(...)`\n\n, causing TypeScript errors (\"Property 'mock' does not exist\") and potential runtime TypeError.`vi.mock`\n\nis now correctly typed.\n\n[bun build bugfixes](#bun-build-bugfixes)\n\n- Fixed: 2 different sourcemap sorting bugs. Please continue letting us know if you run into sourcemap-related issues.\n\n[CSS and styling](#css-and-styling)\n\n- Fixed: CSS view-transition pseudo-elements now support class selector arguments (e.g.,\n`::view-transition-old(.slide-out)`\n\n,`::view-transition-new(.fade-in)`\n\n,`::view-transition-group(.card)`\n\n,`::view-transition-image-pair(.hero)`\n\n), resolving \"Unexpected token: .\" errors during parsing/bundling. These selectors now parse, minify, and serialize correctly. - Fixed: CSS minifier now processes\n`@layer`\n\nblocks, ensuring`color-scheme`\n\nrules receive the required`--buncss-light`\n\n/`--buncss-dark`\n\nvariable injections and`prefers-color-scheme`\n\nfallbacks for browsers without`light-dark()`\n\nsupport.\n\n[bun install bugfixes](#bun-install-bugfixes)\n\n- Fixed:\n`bun update --interactive`\n\n(including`--latest`\n\n) updated`package.json`\n\nbut did not install the selected updates. It now installs the updated dependencies and refreshes`node_modules`\n\n, so no extra`bun install`\n\nis required. - Fixed:\n`bun update --interactive`\n\nno longer strips`npm:`\n\nalias prefixes when updating dependencies in`package.json`\n\n. Aliases and range operators are preserved when bumping versions (e.g.,`npm:@jsr/std__semver@1.0.5 → npm:@jsr/std__semver@1.0.6`\n\n,`npm:@types/no-deps@^1.0.0 → npm:@types/no-deps@^2.0.0`\n\n). - Fixed:\n`bun install`\n\nleft optional peerDependencies unresolved in isolated installs, causing inconsistent peer resolutions, duplicate package copies in`node_modules/.bun`\n\n, and TypeScript type incompatibilities in monorepos (e.g. Elysia + plugins). Optional peers now resolve to an installed package when available, improving deduplication and linker behavior. - Fixed:\n`bun install`\n\nno longer conflates`git+ssh`\n\nand`git+https`\n\n(or other protocol prefixes) references to the same repository; each specifier is resolved and recorded independently. - Fixed: GitHub dependencies with custom protocol prefixes (e.g., git+https://github.com/owner/repo#v1.2.3) are now recognized as GitHub tag downloads, enabling the faster HTTP download path and reducing install time. Improved recognition of GitHub shorthand (owner/repo and owner/repo#branch) during dependency resolution increases reliability for hosted git installs.\n\n[Runtime and performance](#runtime-and-performance)\n\n- Fixed: Global\n`~/.bunfig.toml`\n\ncould be loaded more than once in a single run, leading to duplicate configuration application and unexpected behavior. Bun now guarantees the config is loaded at most once per run. - Fixed: Crash when parsing MySQL OK packets with truncated or empty payloads. An integer underflow could produce an oversized read and trigger an overflow panic. Remaining bytes are now safely clamped, improving reliability when handling minimal responses (e.g., queries that return no rows).\n- Fixed: A crash in\n`Bun.CookieMap#delete`\n\nin certain cases. - Fixed: ANSI color support is now detected per stream (stdout vs stderr). This resolves missing colors in errors/crash reports and test diffs, and prevents misrendered box-drawing characters in interactive commands (e.g., publish, outdated, create, init, update) when the terminal doesn't support color.\n- Fixed: Interactive UIs and installer output only use box-drawing characters when stdout supports ANSI, avoiding garbled tables and lines in plain terminals.\n- Fixed: Hot reload terminal-clearing logic respects stdout color capability, avoiding unnecessary escape sequences in non-ANSI environments.\n- Fixed: Test framework output (expect diffs and matcher messages) consistently respects stderr color support for readable failure output.\n- Fixed: Crash reports on glibc-based Linux could show severely truncated stack traces (sometimes only the signal handler frame). Bun now uses Zig's\n`std.debug.captureStackTrace`\n\nfor more complete traces, falling back to glibc`backtrace()`\n\nwhen it provides more frames (e.g., on some ARM systems).\n\n[Module resolution](#module-resolution)\n\n- Fixed: Requiring an ES module with top‑level await via\n`require()`\n\nor`import.meta.require`\n\nwould throw and leave a partially initialized module in the cache, causing subsequent`import()`\n\nor`require()`\n\nto behave incorrectly. The failed module is now evicted from the cache on error so a later dynamic`import()`\n\nloads and evaluates it correctly.\n\n[TypeScript and types](#typescript-and-types)\n\n- Fixed: TypeScript types for Blob, ReadableStream, and Response now include\n`text()`\n\n,`bytes()`\n\n,`json()`\n\n,`formData()`\n\n, and`arrayBuffer()`\n\nconvenience methods, resolving errors like \"Type 'Blob' is missing ... json, formData\" when using`response.blob()`\n\n. - Fixed: TypeScript definitions for\n`Bun.spawn`\n\nand`spawnSync`\n\nnow include missing options and match runtime behavior. You can use`detached`\n\n,`onDisconnect`\n\n(fires when the IPC channel closes), and`lazy`\n\n(defer stdout/stderr reads until accessed). Also clarified IPC lifecycle ordering with`onExit`\n\n. - Fixed: spawn/spawnSync option shapes are unified via\n`Bun.Spawn.BaseOptions`\n\nin the types; the older`Spawn.OptionsObject`\n\nalias is deprecated. Use`BaseOptions`\n\nor the specific spawn/spawnSync option types going forward.\n\n[Web Crypto](#web-crypto)\n\n- Fixed: Web Crypto\n`crypto.exportKey(\"jwk\")`\n\nfor EC private keys sometimes produced a shorter-than-required \"d\" parameter (missing leading-zero padding), violating RFC 7518 and causing import failures in Chrome. Bun now pads \"d\" to the correct length for P-256 (32 bytes), P-384 (48 bytes), and P-521 (66 bytes).", "url": "https://wpnews.pro/news/bun-v1-3-2", "canonical_source": "https://bun.com/blog/bun-v1.3.2", "published_at": "2025-11-08 10:11:00+00:00", "updated_at": "2026-05-22 20:43:27.864914+00:00", "lang": "en", "topics": ["developer-tools", "open-source"], "entities": ["Bun", "Oven"], "alternates": {"html": "https://wpnews.pro/news/bun-v1-3-2", "markdown": "https://wpnews.pro/news/bun-v1-3-2.md", "text": "https://wpnews.pro/news/bun-v1-3-2.txt", "jsonld": "https://wpnews.pro/news/bun-v1-3-2.jsonld"}}