{"slug": "bun-v1-2-23", "title": "Bun v1.2.23", "summary": "Bun v1.2.23 fixes 119 issues and introduces several new features. Key additions include automatic migration from pnpm-lock.yaml to bun.lock, new `--cpu` and `--os` flags for filtering optional dependencies, built-in Redis Pub/Sub support, and concurrent test execution with `test.concurrent`.", "body_md": "This release fixes 119 issues (addressing 412 👍).\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`pnpm-lock.yaml`\n\nin `bun install`\n\n`pnpm-lock.yaml`\n\nin `bun install`\n\n`bun install`\n\nnow automatically migrates `pnpm-lock.yaml`\n\nand `pnpm-workspace.yaml`\n\nfiles to a `bun.lock`\n\n, preserving resolved dependency versions. This includes support for pnpm workspaces and `catalog:`\n\ndependencies.\n\nSwitch from `pnpm install`\n\nto `bun install`\n\nwith a single command:\n\n```\n# In a pnpm project\nbun install\n```\n\n`bun install`\n\nis designed to work with existing Node.js projects. That means you can leverage `bun install`\n\n's incredible performance while still using Node.js as your runtime.\n\nIf your project uses `pnpm-workspace.yaml`\n\n, your package.json is updated to include `\"workspaces\": [\"<each package-name>\"]`\n\n.\n\nThanks to @dylan-conway for implementing this!\n\n[Filter optional dependencies with ](#filter-optional-dependencies-with-cpu-and-os-flags)`--cpu`\n\nand `--os`\n\nflags\n\n`--cpu`\n\nand `--os`\n\nflagsYou can now control which platform-specific `optionalDependencies`\n\nare installed using the new `--cpu`\n\nand `--os`\n\nflags in `bun install`\n\n. This is useful when you're installing dependencies for a different target environment, such as in a Docker container or a CI/CD pipeline.\n\nYou can provide multiple values to install dependencies for several targets at once.\n\n```\n# Install optional dependencies for a Linux ARM64 target\nbun install --os linux --cpu arm64\n\n# Install for both macOS and Linux on x64\nbun install --os darwin --os linux --cpu x64\n\n# Install for all supported platforms\nbun install --os '*' --cpu '*'\n```\n\n[Bun's Redis client now supports Pub/Sub](#bun-s-redis-client-now-supports-pub-sub)\n\nBun's built-in `RedisClient`\n\nnow supports the Publish/Subscribe (Pub/Sub) messaging pattern. You can use the new `.subscribe()`\n\nmethod to listen for messages on specific channels and the `.publish()`\n\nmethod to send messages.\n\nThis enables real-time, event-driven communication patterns directly within your Bun applications.\n\n``` js\nimport { RedisClient } from \"bun\";\n\nconst subscriber = new RedisClient(\"redis://localhost:6379\");\nawait subscriber.connect();\n\nawait subscriber.subscribe(\"my-channel\", (message, channel) => {\n  console.log(`Received message: \"${message}\" from channel: \"${channel}\"`);\n  // Received message: \"Hello from Bun!\" from channel: \"my-channel\"\n});\njs\nimport { RedisClient } from \"bun\";\n\nconst publisher = new RedisClient(\"redis://localhost:6379\");\nawait publisher.connect();\n\n// After a short delay to ensure the subscriber is ready\nsetTimeout(() => {\n  publisher.publish(\"my-channel\", \"Hello from Bun!\");\n}, 100);\n```\n\nThanks to @markovejnovic for the contribution\n\n[Concurrent ](#concurrent-bun-test)`bun test`\n\n`bun test`\n\n`bun test`\n\nnow supports running multiple `async`\n\ntests concurrently within the same file using `test.concurrent`\n\n. This can significantly speed up test suites that are I/O-bound, such as those making network requests or interacting with a database.\n\n``` js\nimport { test, expect } from \"bun:test\";\n\n// These three tests will run in parallel.\n// The total execution time will be ~1 second, not 3 seconds.\ntest.concurrent(\"sends a request to server 1\", async () => {\n  const response = await fetch(\"https://example.com/server-1\");\n  expect(response.status).toBe(200);\n});\n\ntest.concurrent(\"sends a request to server 2\", async () => {\n  const response = await fetch(\"https://example.com/server-2\");\n  expect(response.status).toBe(200);\n});\n\n// Chain with .each, .only, or other modifiers:\ntest.concurrent.each([\n  \"https://example.com/server-4\",\n  \"https://example.com/server-5\",\n  \"https://example.com/server-6\",\n])(\"sends a request to server %s\", async (url) => {\n  const response = await fetch(url);\n  expect(response.status).toBe(200);\n});\n```\n\nRun groups of tests concurrently with `describe.concurrent`\n\n.\n\n``` js\nimport { describe, test, expect } from \"bun:test\";\n\ndescribe.concurrent(\"server tests\", () => {\n  test(\"sends a request to server 1\", async () => {\n    const response = await fetch(\"https://example.com/server-1\");\n    expect(response.status).toBe(200);\n  });\n});\n\ntest(\"serial test\", () => {\n  expect(1 + 1).toBe(2);\n});\n```\n\nBy default, a maximum of 20 tests will run concurrently. You can change this with the `--max-concurrency`\n\nflag.\n\n`concurrentTestGlob`\n\nto make specific files run concurrently\n\nTo make specific files run concurrently, you can use the `concurrentTestGlob`\n\noption in `bunfig.toml`\n\n.\n\n```\n[test]\nconcurrentTestGlob = \"**/integration/**/*.test.ts\"\n\n# You can also provide an array of patterns.\n# concurrentTestGlob = [\n#   \"**/integration/**/*.test.ts\",\n#   \"**/*-concurrent.test.ts\",\n# ]\n```\n\nWhen using `concurrentTestGlob`\n\n, all tests in the files matching the glob will run concurrently.\n\n`test.serial`\n\nto make specific tests sequential\n\nWhen you use `describe.concurrent`\n\n, `--concurrent`\n\n, or `concurrentTestGlob`\n\n, you might still want to leave some tests sequential. You can do this by using the new `test.serial`\n\nmodifier.\n\n``` js\nimport { test, expect } from \"bun:test\";\n\ndescribe.concurrent(\"concurrent tests\", () => {\n  test(\"async test\", async () => {\n    await fetch(\"https://example.com/server-1\");\n    expect(1 + 1).toBe(2);\n  });\n\n  test(\"async test #2\", async () => {\n    await fetch(\"https://example.com/server-2\");\n    expect(1 + 1).toBe(2);\n  });\n\n  test.serial(\"serial test\", () => {\n    expect(1 + 1).toBe(2);\n  });\n});\n```\n\n[Run tests in a random order with ](#run-tests-in-a-random-order-with-randomize)`--randomize`\n\n`--randomize`\n\nConcurrent tests sometimes expose unexpected test dependencies on execution order or shared state. You can use the `--randomize`\n\nflag to run tests in a random order to make it easier to find these dependencies.\n\nWhen you use `--randomize`\n\n, Bun will output the seed for that specific run. To reproduce the exact same test order for debugging, you can use the `--seed`\n\nflag with the printed value. Using `--seed`\n\nautomatically enables randomization.\n\n```\n# Run tests in a random order\nbun test --randomize\n# The seed is printed in the test summary\n# ... test output ...\n#  --seed=12345\n# 2 pass\n# 8 fail\n# Ran 10 tests across 2 files. [50.00ms]\n\n# Reproduce the same run order using the seed\nbun test --seed 12345\n```\n\n`bun test`\n\nnow supports chaining qualifiers\n\n`bun test`\n\nnow supports chaining qualifiersYou can now chain qualifiers like `.failing`\n\n, `.skip`\n\n, `.only`\n\n, and `.each`\n\non `test`\n\nand `describe`\n\n. Previously, this would result in an error.\n\n``` js\nimport { test, expect } from \"bun:test\";\n\n// This test is expected to fail, and it runs for each item in the array.\ntest.failing.each([1, 2, 3])(\"each %i\", (i) => {\n  if (i > 0) {\n    throw new Error(\"This test is expected to fail.\");\n  }\n});\n```\n\n[Stricter ](#stricter-bun-test-in-ci-environments)`bun test`\n\nin CI environments\n\n`bun test`\n\nin CI environmentsTo prevent accidental commits, `bun test`\n\nwill now throw an error in CI environments (where `CI=true`\n\n) in two new scenarios:\n\n- If a test file contains\n`test.only()`\n\n. - If a snapshot test (\n`.toMatchSnapshot()`\n\nor`.toMatchInlineSnapshot()`\n\n) tries to create a new snapshot without the`--update-snapshots`\n\nflag.\n\nThis helps prevent temporarily focused tests or unintentional snapshot changes from being merged. To disable this behavior, you can set the environment variable `CI=false`\n\n.\n\n[Test execution order improvements](#test-execution-order-improvements)\n\nThe test runner's execution logic has been rewritten for improved reliability and predictability. This resolves a large number of issues where `describe`\n\nblocks and hooks (`beforeAll`\n\n, `afterAll`\n\n, etc.) would execute in a slightly unexpected order. The new behavior is more consistent with test runners like Vitest.\n\n[Concurrent test limitations](#concurrent-test-limitations)\n\n`expect.assertions()`\n\nand`expect.hasAssertions()`\n\nare not supported when using`test.concurrent`\n\nor`describe.concurrent`\n\n.`toMatchSnapshot()`\n\nis not supported, but`toMatchInlineSnapshot()`\n\nis.`beforeAll`\n\nand`afterAll`\n\nhooks are not executed concurrently.\n\nThanks to @pfgithub for all of these big improvements to `bun test`\n\n!\n\n`bun feedback`\n\n`bun feedback`\n\nIn the next version of Bun\n\n— Jarred Sumner (@jarredsumner)\n\nbun feedback <files or text> makes it easier to send feedback about Bun to the Bun team[pic.twitter.com/CkJAKwllzU][September 16, 2025]\n\n[Node.js compatibility improvements](#node-js-compatibility-improvements)\n\n#### node:http\n\n`http.createServer`\n\nnow supports the `CONNECT`\n\nmethod. This allows for creating HTTP proxies with Bun.\n\n#### node:dns\n\n`dns.resolve`\n\n's callback now matches Node.js by no longer passing an extra `hostname`\n\nargument. `dns.promises.resolve`\n\nnow correctly returns an array of strings instead of objects for A/AAAA records.\n\n#### node:worker_threads\n\nA bug where `MessagePort`\n\ncommunication would fail after being transferred to a `Worker`\n\nwhen using `port.on('message', ...)`\n\nor `port.addEventListener('message', ...)`\n\n. This was caused by a different between Web Workers and `worker_threads`\n\n.\n\n#### node:crypto\n\nA hypothetical crash in `crypto.createSign().sign()`\n\nwhen using an Elliptic Curve (EC) key in JWK format with `dsaEncoding: 'ieee-p1363'`\n\nhas been fixed.\n\n#### node:http2\n\nA memory leak when closing sockets has been fixed.\n\n#### node:net\n\nA handle leak in `net.connect()`\n\nthat caused memory usage to grow when making many connections has been resolved.\n\n#### node:tty\n\nOn Windows, TTY raw mode (`process.stdin.setRawMode(true)`\n\n) now correctly handles terminal VT control sequences, improving compatibility with Node.js and enabling features like bracketed paste mode.\n\n[Use system's trusted certificates with ](#use-system-s-trusted-certificates-with-use-system-ca)`--use-system-ca`\n\n`--use-system-ca`\n\nBun can now be configured to use the operating system's trusted root certificates for establishing TLS connections, in addition to the built-in Mozilla CA store. This is useful in corporate environments with custom Certificate Authorities (CAs) or for trusting locally installed self-signed certificates.\n\nTo enable this functionality, either use the new `--use-system-ca`\n\ncommand-line flag or set the `NODE_USE_SYSTEM_CA=1`\n\nenvironment variable, which aligns Bun with Node.js's behavior.\n\n```\n# This command will use the OS's trusted CAs to validate the certificate\n# for \"internal.service.corp\".\nbun run --use-system-ca index.js\njs\n# index.js\nconst response = await fetch(\"https://internal.service.corp\");\nconsole.log(response.status);\n```\n\n`process.report.getReport()`\n\nis now implemented on Windows\n\n`process.report.getReport()`\n\nis now implemented on WindowsThe Node.js-compatible API `process.report.getReport()`\n\nis now fully implemented on Windows. Previously, this would throw a \"Not implemented\" error. This function generates a comprehensive diagnostic report about the current process, including system information, JavaScript heap statistics, stack traces, and loaded shared libraries.\n\nThis change improves compatibility with tools that rely on this API for diagnostics or environment detection.\n\n``` js\n// On Windows, this now returns a detailed report object.\nconst report = process.report.getReport();\n\nconsole.log(report.header.osVersion); // e.g., \"Windows 11 Pro\"\nconsole.log(report.header.cpus.length > 0); // true\nconsole.log(report.javascript.heap.heapSpaces.length > 0); // true\n```\n\n[Codesigning for Windows in ](#codesigning-for-windows-in-bun-build-compile)`bun build --compile`\n\n`bun build --compile`\n\n`bun build --compile`\n\ncan create standalone executables from a JavaScript or TypeScript entrypoint. On Windows, these executables are often based on a pre-signed `bun.exe`\n\nbinary. Previously, when Bun embedded the application code and assets, it would invalidate this original signature, preventing developers from applying their own code signing certificate.\n\nThis release introduces automatic \"Authenticode\" signature stripping. When you create an executable, Bun now removes the original signature, allowing you to sign the compiled binary with your own certificate using standard Windows tools like `signtool.exe`\n\n. This is essential for distributing trusted applications to Windows users.\n\n```\n# 1. Compile your application into a standalone executable\nbun build ./index.ts --compile --outfile my-app.exe\n\n# 2. Sign the resulting executable with your own certificate\nsigntool.exe sign /f MyCert.pfx /p MyPassword my-app.exe\n```\n\n`Bun.build`\n\ngets a new `jsx`\n\nconfiguration object\n\n`Bun.build`\n\ngets a new `jsx`\n\nconfiguration objectConfiguration for JSX transforms in `Bun.build`\n\nis now centralized in a new `jsx`\n\nobject. This includes options previously configured via `tsconfig.json`\n\n, like `jsxFactory`\n\n, `jsxFragment`\n\n, and `jsxImportSource`\n\n.\n\n```\nawait Bun.build({\n  entrypoints: [\"./index.jsx\"],\n  outdir: \"./dist\",\n  jsx: {\n    runtime: \"automatic\", // \"automatic\" or \"classic\"\n    importSource: \"preact\", // defaults to \"react\"\n    factory: \"h\", // defaults to \"React.createElement\"\n    fragment: \"Fragment\", // defaults to \"React.Fragment\"\n    development: false, // use `jsx-dev` runtime, defaults to `false`\n    sideEffects: false,\n  },\n});\n```\n\n`sql.array`\n\nhelper in Bun.SQL\n\n`sql.array`\n\nhelper in Bun.SQLThe `sql.array`\n\nhelper in Bun.SQL makes it easy to work with PostgreSQL array types. You can insert arrays into array columns and specify the PostgreSQL data type for proper casting.\n\n``` js\nimport { sql } from \"bun\";\n\n// Insert an array of text values\nawait sql`\n  INSERT INTO users (name, roles)\n  VALUES (${\"Alice\"}, ${sql.array([\"admin\", \"user\"], \"TEXT\")})\n`;\n\n// Update with array values using sql object notation\nawait sql`\n  UPDATE users\n  SET ${sql({\n    name: \"Bob\",\n    roles: sql.array([\"moderator\", \"user\"], \"TEXT\"),\n  })}\n  WHERE id = ${userId}\n`;\n\n// Works with JSON/JSONB arrays\nconst jsonData = await sql`\n  SELECT ${sql.array([{ a: 1 }, { b: 2 }], \"JSONB\")} as data\n`;\n\n// Supports various PostgreSQL types\nawait sql`SELECT ${sql.array([1, 2, 3], \"INTEGER\")} as numbers`;\nawait sql`SELECT ${sql.array([true, false], \"BOOLEAN\")} as flags`;\nawait sql`SELECT ${sql.array([new Date()], \"TIMESTAMP\")} as dates`;\n```\n\nThe `sql.array`\n\nhelper supports all major PostgreSQL array types including `TEXT`\n\n, `INTEGER`\n\n, `BIGINT`\n\n, `BOOLEAN`\n\n, `JSON`\n\n, `JSONB`\n\n, `TIMESTAMP`\n\n, `UUID`\n\n, `INET`\n\n, and many more.\n\nThanks to @cirospaciari for the contribution!\n\n[Top level await improvements](#top-level-await-improvements)\n\nBun's bundler now has improved support for top-level await.\n\nWhen there are cylical dependencies using top-level await, Bun will now wrap modules in `await Promise.all`\n\nto ensure they are all loaded. We've also fixed a couple edgecases that could cause the `async`\n\nkeyword to be missing from bundled modules in certain cases.\n\nThanks to @dylan-conway for implementing this!\n\n[Bundler & dev-server bugfixes:](#bundler-dev-server-bugfixes)\n\n- Improved: syntax error messages for invalid escape sequences, like\n`\\\"`\n\n, outside of string literals. - Fixed: A bug causing sourcemap line numbers to be off-by-one or more in Chrome DevTools\n- Fixed: A regression in the minifier where\n`new Array()`\n\nwith a ternary expression would be bundled incorrectly has been fixed. - Fixed:\n`bun build`\n\nproducing output that would hang indefinitely when bundling code with cyclic asynchronous module dependencies. - Fixed: a crash that occurred when a macro returned a complex or deeply-nested object or array.\n\n[bun install bugfixes:](#bun-install-bugfixes)\n\n- Fixed: An integer overflow when parsing package versions, which could cause\n`bun install`\n\nto crash or select the wrong version of a package. This affected packages like`@google/gemini-cli@nightly`\n\nand`@scratch/paper`\n\nthat use large numbers in their version strings. - Fixed a bug where\n`bun install`\n\ncould fail with an`ETXTBUSY`\n\n(Text file busy) error when linking package binaries. - Fixed a crash on Windows when running\n`bun outdated`\n\nor`bun install`\n\ncaused by a race condition.\n\n[bun test bugfixes:](#bun-test-bugfixes)\n\n- Fixed: An uncaught promise rejection in an\n`async`\n\ntest no longer causes the test runner to hang. - Fixed:\n`test()`\n\nand`afterAll()`\n\nare no longer allowed inside another`test()`\n\ncallback. Previously, inner`test`\n\ncallbacks were simply ignored. Bun will now throw an error instead of silently failing or producing unexpected behavior. - Fixed: When\n`test.only`\n\nis nested inside`describe.only`\n\n, only the innermost`.only`\n\ntests are executed. - Fixed: When using\n`describe.only`\n\n,`beforeAll`\n\nhooks in`describe`\n\nblocks not marked with`.only`\n\nwill be correctly skipped. - Fixed: A failure in an\n`async beforeEach`\n\nhook now correctly prevents the corresponding test from running. - Fixed: Test hooks like\n`beforeAll`\n\nand`beforeEach`\n\nnow support a timeout option and will fail if they exceed the specified duration. - Fixed: An\n`afterAll`\n\nhook will now run even if a corresponding`beforeAll`\n\nhook fails, which aligns with Jest's behavior and is useful for cleanup tasks. - Fixed: Throwing an error in a\n`beforeAll`\n\nhook loaded via`--preload`\n\nnow correctly halts test execution across all files. - Fixed: When an error is thrown inside a\n`describe`\n\nblock, any nested`describe`\n\nblocks are now correctly skipped. - Fixed: An issue where\n`describe.todo()`\n\nwas incorrectly executed when nested inside`describe.only()`\n\n. - Fixed: A passing test inside a\n`describe.todo()`\n\nblock is now handled correctly. - Fixed: An error in an async\n`beforeEach`\n\nhook is now reported correctly, instead of being masked as an \"unhandled error between tests\". - Fixed: An exception when using custom matchers from libraries like\n`jest-dom`\n\nthat rely on`this.utils.RECEIVED_COLOR`\n\nand`this.utils.EXPECTED_COLOR`\n\n. Additionally,`vi.resetAllMocks`\n\n,`vi.useFakeTimers`\n\n, and`vi.useRealTimers`\n\nare now stubbed until we finish implementing them. - Fixed:\n`bun test`\n\nnow shows clearer error messages and help text for the`--reporter`\n\nand`--coverage-reporter`\n\nflags. - Fixed: A bug where\n`bun test`\n\nwould not correctly load test files when using a`.`\n\nin the path.\n\n[Bug fixes and reliability improvements](#bug-fixes-and-reliability-improvements)\n\n- Fixed:\n`YAML.parse()`\n\nnow throws a`SyntaxError`\n\nfor invalid input, matching the behavior of`JSON.parse()`\n\n. - Fixed a bug where\n`fetch()`\n\nwould only support single-frame`zstd`\n\n-compressed responses sent with`Transfer-Encoding: chunked`\n\n. Bun's decompressor now correctly handles multi-frame`zstd`\n\nstreams, ensuring the full response body is received. - Fixed: A bug where\n`fetch()`\n\nwith an`AbortSignal`\n\nwould not abort if the signal was triggered while the underlying socket was connecting (only after it connected or failed to connect). This particularly affected`AbortSignal.timeout()`\n\nwhen making requests to unresponsive servers. - Fixed: A bug when console.logging an\n`Error`\n\nobject could display a truncated stack trace. - Fixed a bug preventing\n`Bun.redis`\n\nfrom connecting to Redis/Valkey servers over TLS. This affected connections using`rediss://`\n\nor the`tls: true`\n\noption. - Fixed: infinite loop when logging an\n`Error`\n\nobject with a circular reference, like`error.stack = error`\n\nor a circular`error.cause`\n\nchain. - Fixed a rare crash in\n`Bun.serve`\n\nthat could occur during garbage collection. - Fixed a crash that occurred when a\n`Bun.plugin`\n\n's`onResolve`\n\nhandler returned`undefined`\n\nor`null`\n\n. - Fixed an assertion failure on Windows caused by an incorrect file path.\n- Fixed: A bug in\n`Bun.sql`\n\n's`postgres`\n\ndriver where`NUMERIC`\n\nvalues with many digits were parsed incorrectly has been resolved. - Fixed: The\n`install.sh`\n\nscript now prioritizes`~/.bash_profile`\n\nover`~/.bashrc`\n\nwhen updating the`PATH`\n\n, aligning with standard Bash practices. - Internal: LeakSanitizer to our CI pipeline to automatically detect native memory leaks.\n- Fixed: A crash that could occur when a UDP socket is active while the Bun process is exiting.\n- Fixed: A very rare race condition that could cause\n`fetch()`\n\nto crash when handling many simultaneous redirects while an`AbortSignal`\n\nwas active. - Fixed: A stability issue in\n`Bun.serve`\n\nimpacting large request bodies - Fixed:\n`BUN_CONFIG_VERBOSE_FETCH=curl`\n\nnow prints the request body for`fetch`\n\nrequests with`Content-Type: application/x-www-form-urlencoded`\n\n. - Fixed a crash when a large number of command-line arguments were passed to the current process and process.argv was accessed.\n- Fixed: The current working directory in stack traces is now dimmed, improving readability and helping to identify local files.\n- Fixed:\n`Bun.SQL`\n\n's MySQL driver did not work on Windows. - Upgraded libuv to v1.51.0, improving I/O reliability\n- Fixed: Bun's browser error modal is now 250 KB smaller, making it faster to load.\n- Fixed an issue where\n`npm install bun`\n\nwould fail on Alpine Linux for`arm64`\n\n.", "url": "https://wpnews.pro/news/bun-v1-2-23", "canonical_source": "https://bun.com/blog/bun-v1.2.23", "published_at": "2025-09-28 10:11:00+00:00", "updated_at": "2026-05-22 20:44:46.173846+00:00", "lang": "en", "topics": ["developer-tools", "open-source"], "entities": ["Bun", "Oven", "Dylan Conway"], "alternates": {"html": "https://wpnews.pro/news/bun-v1-2-23", "markdown": "https://wpnews.pro/news/bun-v1-2-23.md", "text": "https://wpnews.pro/news/bun-v1-2-23.txt", "jsonld": "https://wpnews.pro/news/bun-v1-2-23.jsonld"}}