{"slug": "bun-1-3", "title": "Bun 1.3", "summary": "Bun 1.3 is a major update that transforms Bun into a full-stack JavaScript runtime with built-in frontend development support, including hot reloading, React Fast Refresh, and a production bundler. The release adds first-class MySQL and Redis clients alongside existing database support, improved routing with parameterized and catch-all routes, and better WebSocket and HTTP handling. It also introduces isolated installs and workspace improvements, positioning Bun as a comprehensive tool for building both backend and frontend JavaScript applications.", "body_md": "Bun 1.3 is our biggest release yet.\n\n```\ncurl -fsSL https://bun.sh/install | bash\npowershell -c \"irm bun.sh/install.ps1 | iex\"\nnpm install -g 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[Full‑stack JavaScript runtime](#full-stack-javascript-runtime)\n\nBun 1.3 turns Bun into a batteries‑included full‑stack JavaScript runtime. We’ve added first-class support for frontend development with all the features you expect from modern JavaScript frontend tooling.\n\nThe highlights:\n\n- Full‑stack dev server (with hot reloading, browser -> terminal console logs) built into\n`Bun.serve()`\n\n- Builtin MySQL client, alongside our existing Postgres and SQLite clients\n- Builtin Redis client\n- Better routing, cookies, WebSockets, and HTTP ergonomics\n- Isolated installs, catalogs,\n`minimumRelease`\n\n, and more for workspaces - Many, many Node.js compatibility improvements\n\nThis is the start of a 1.3 series focused on making Bun the best way to build backend and frontend applications with JavaScript.\n\n[Frontend Development](#frontend-development)\n\nThe web starts with HTML, and so does building frontend applications with Bun. You can now run HTML files directly with Bun.\n\nThis isn't a static file server. This uses Bun's native JavaScript & CSS transpilers & bundler to bundle your React, CSS, JavaScript, and HTML files. Every day, we hear from developers switching from tools like Vite to Bun.\n\n[Hot Reloading](#hot-reloading)\n\nBun's frontend dev server has builtin support for Hot Module Replacement, including React Fast Refresh. This lets you test your changes as you write them, without having to reload the page, and the [ import.meta.hot](https://bun.com/docs/bundler/hmr) API lets framework authors implement hot reloading support in their frameworks on top of Bun's frontend dev server.\n\nWe implemented the filesystem watcher in native code using the fastest platform-specific APIs available (`kqueue`\n\non macOS, `inotify`\n\non Linux, and `ReadDirectoryChangesW`\n\non Windows).\n\n[Production Builds](#production-builds)\n\nWhen it's time to build for production, run `bun build --production`\n\nto bundle your app.\n\n```\nbun build ./index.html --production --outdir=dist\n```\n\n[Getting Started](#getting-started)\n\nTo get started, run `bun init --react`\n\nto scaffold a new project:\n\n```\nbun init\n? Select a project template - Press return to submit.\n❯   Blank\n    React\n    Library\n\n# Or use any of these variants:\nbun init --react\nbun init --react=tailwind\nbun init --react=shadcn\n```\n\nBun is used for frontend development by companies like Midjourney.\n\nVisit [the docs](/docs/bundler/html) to learn more!\n\n[Full-stack Development](#full-stack-development)\n\nOne of the things that makes JavaScript great is that you can write both the frontend and backend in the same language.\n\nIn Bun v1.2, we introduced [HTML imports](https://bun.com/docs/bundler/html) and in Bun v1.3, we've expanded that to include hot reloading support and built-in routing.\n\n``` python\nimport homepage from \"./index.html\";\nimport dashboard from \"./dashboard.html\";\nimport { serve } from \"bun\";\n\nserve({\n  development: {\n    // Enable Hot Module Reloading\n    hmr: true,\n\n    // Echo console logs from the browser to the terminal\n    console: true,\n  },\n\n  routes: {\n    \"/\": homepage,\n    \"/dashboard\": dashboard,\n  },\n});\n```\n\n#### CORS is simpler now\n\nToday, many apps have to deal with Cross-Origin Resource Sharing (CORS) issues caused by running the backend and the frontend on different ports. In Bun, we make it easy to run your entire app in the same server process.\n\n[Routing](#routing)\n\nWe've added support for parameterized and catch-all routes in Bun.serve(), so you can use the same API for both the frontend and backend.\n\n``` python\nimport { serve, sql } from \"bun\";\nimport App from \"./myReactSPA.html\";\n\nserve({\n  port: 3000,\n  routes: {\n    \"/*\": App,\n\n    \"/api/users\": {\n      GET: async () => Response.json(await sql`SELECT * FROM users LIMIT 10`),\n\n      POST: async (req) => {\n        const { name, email } = await req.json();\n        const [user] = await sql`\n          INSERT INTO users ${sql({ name, email })}\n          RETURNING *;\n        `;\n        return Response.json(user);\n      },\n    },\n\n    \"/api/users/:id\": async (req) => {\n      const { id } = req.params;\n      const [user] = await sql`SELECT * FROM users WHERE id = ${id} LIMIT 1`;\n      if (!user) return new Response(\"User not found\", { status: 404 });\n      return Response.json(user);\n    },\n\n    \"/healthcheck.json\": Response.json({ status: \"ok\" }),\n  },\n});\n```\n\nRoutes support dynamic path parameters like `:id`\n\n, different handlers for different HTTP methods, and serving static files or HTML imports alongside API routes. Everything runs in a single process. Just define your routes, and Bun matches them for you.\n\n[Compile full-stack apps to a standalone executable](#compile-full-stack-apps-to-a-standalone-executable)\n\nBun's bundler can now bundle both frontend and backend applications in the same build. And we've expanded support for [single-file executables](/docs/bundler/executables) to include full-stack apps.\n\n```\nbun build --compile ./index.html --outfile myapp\n```\n\nFull-stack React app compiled with bun build --compile serves the same index.html file 1.8x faster than nginx\n\n— Jarred Sumner (@jarredsumner)[https://t.co/tPU3KdHzjU][pic.twitter.com/XQhJPlaqxP][June 20, 2025]\n\nYou can use standalone executables with other Bun features like `Bun.serve()`\n\nroutes, `Bun.sql`\n\n, `Bun.redis`\n\n, or any other Bun APIs to create portable self-contained applications that run anywhere.\n\n[Bun.SQL - MySQL, MariaDB, and SQLite support](#bun-sql-mysql-mariadb-and-sqlite-support)\n\nBun.SQL goes from builtin a PostgreSQL client to a unified MySQL/MariaDB, PostgreSQL, and SQLite API. One incredibly fast builtin database library supporting the most popular database adapters, with zero extra dependencies.\n\n``` js\nimport { sql, SQL } from \"bun\";\n\n// Connect to any database with the same API\nconst postgres = new SQL(\"postgres://localhost/mydb\");\nconst mysql = new SQL(\"mysql://localhost/mydb\");\nconst sqlite = new SQL(\"sqlite://data.db\");\n\n// Defaults to connection details from env vars\nconst seniorAge = 65;\nconst seniorUsers = await sql`\n  SELECT name, age FROM users\n  WHERE age >= ${seniorAge}\n`;\n```\n\nWhile existing npm packages like `postgres`\n\nand `mysql2`\n\npackages perform great in Bun, offering a builtin API for such common database needs brings incredible performance gains, and reduces the number of dependencies your project needs to get started.\n\nBun 1.3 also adds a `sql.array`\n\nhelper in `Bun.SQL`\n\n, making 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\n[PostgreSQL enhancements](#postgresql-enhancements)\n\nBun's built-in PostgreSQL client has received comprehensive enhancements that make it more powerful and production-ready.\n\n**Simple query protocol for multi-statement queries.** You can now use the simple query protocol by calling `.simple()`\n\non your query:\n\n```\nawait sql`\n  SELECT 1;\n  SELECT 2;\n`.simple();\n```\n\nThis is particularly useful for database migrations:\n\n```\nawait sql`\n  CREATE TABLE users (\n    id SERIAL PRIMARY KEY,\n    name TEXT NOT NULL,\n    email TEXT UNIQUE NOT NULL\n  );\n\n  CREATE INDEX idx_users_email ON users(email);\n\n  INSERT INTO users (name, email)\n  VALUES ('Admin', 'admin@example.com');\n`.simple();\n```\n\n**Disable prepared statements with prepare: false.** Useful for working with PGBouncer in transaction mode or debugging query execution plans:\n\n``` js\nconst sql = new SQL({\n  prepare: false, // Disable prepared statements\n});\n```\n\n**Connect via Unix domain sockets.** For applications running on the same machine as your PostgreSQL server, Unix domain sockets provide better performance:\n\n```\nawait using sql = new SQL({\n  path: \"/tmp/.s.PGSQL.5432\",  // Full path to socket\n  user: \"postgres\",\n  password: \"postgres\",\n  database: \"mydb\"\n});\n```\n\n**Runtime configuration through connection options.** Set runtime parameters via the connection URL or options object:\n\n```\n// Via URL\nawait using db = new SQL(\n  \"postgres://user:pass@localhost:5432/mydb?search_path=information_schema\",\n  { max: 1 }\n);\n\n// Via connection object\nawait using db = new SQL(\"postgres://user:pass@localhost:5432/mydb\", {\n  connection: {\n    search_path: \"information_schema\",\n    statement_timeout: \"30s\",\n    application_name: \"my_app\"\n  },\n  max: 1\n});\n```\n\n**Dynamic column operations.** Building SQL queries dynamically is now easier with powerful helpers:\n\n``` js\nconst user = { name: \"Alice\", email: \"alice@example.com\", age: 30 };\n\n// Insert only specific columns\nawait sql`INSERT INTO users ${sql(user, \"name\", \"email\")}`;\n\n// Update specific fields\nconst updates = { name: \"Alice Smith\", email: \"alice.smith@example.com\" };\nawait sql`UPDATE users SET ${sql(\n  updates,\n  \"name\",\n  \"email\",\n)} WHERE id = ${userId}`;\n\n// WHERE IN with arrays\nawait sql`SELECT * FROM users WHERE id IN ${sql([1, 2, 3])}`;\n\n// Extract field from array of objects\nconst users = [{ id: 1 }, { id: 2 }, { id: 3 }];\nawait sql`SELECT * FROM orders WHERE user_id IN ${sql(users, \"id\")}`;\n```\n\n**PostgreSQL array type support.** The `sql.array()`\n\nhelper makes inserting and working with PostgreSQL arrays straightforward:\n\n```\n// Insert a text array\nawait sql`\n  INSERT INTO users (name, roles)\n  VALUES (${\"Alice\"}, ${sql.array([\"admin\", \"user\"], \"TEXT\")})\n`;\n\n// Supported types: INTEGER, REAL, TEXT, BLOB, BOOLEAN, TIMESTAMP, JSONB, UUID\nawait sql`SELECT ${sql.array([1, 2, 3], \"INTEGER\")} as numbers`;\n```\n\n**Proper null handling in array results.** Bun 1.3 now correctly preserves null values in array results:\n\n``` js\nconst result = await sql`SELECT ARRAY[0, 1, 2, NULL]::integer[]`;\nconsole.log(result[0].array); // [0, 1, 2, null]\n```\n\nOther improvements we've made to PostgreSQL:\n\n**Binary data types and custom OIDs**- Now handled correctly** Improved prepared statement lifecycle**- Better error messages for parameter mismatches** Pipelined query error handling**- No longer causes connection disconnection** TIME and TIMETZ column support**- Correctly decoded in binary protocol** All error classes exported**-`PostgresError`\n\n,`SQLiteError`\n\n,`MySQLError`\n\nfor type-safe error handling**String arrays in WHERE IN clauses**- Now work correctly** Connection failure handling**- Throws catchable errors instead of crashing** Large batch inserts fixed**- No longer fail with \"index out of bounds\" errors** Process shutdown improvements**- No longer hangs with pending queries** NUMERIC value parsing**- Correctly handles values with many digits- Properly implemented`flush()`\n\nmethod**DATABASE_URL options precedence**- Handled correctly\n\n[SQLite enhancements](#sqlite-enhancements)\n\n** Database.deserialize() with configuration options.** When deserializing SQLite databases, you can now specify additional options:\n\n``` js\nimport { Database } from \"bun:sqlite\";\n\nconst serialized = db.serialize();\n\nconst deserialized = Database.deserialize(serialized, {\n  readonly: true, // Open in read-only mode\n  strict: true, // Enable strict mode\n  safeIntegers: true, // Return BigInt for large integers\n});\n```\n\n**Column type introspection with columnTypes and declaredTypes.** Statement objects now expose type information about result columns:\n\n``` js\nimport { Database } from \"bun:sqlite\";\n\nconst db = new Database(\":memory:\");\ndb.run(\"CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)\");\ndb.run(\"INSERT INTO users VALUES (1, 'Alice', 30)\");\n\nconst stmt = db.query(\"SELECT * FROM users\");\n\n// Get declared types from the schema\nconsole.log(stmt.declaredTypes); // [\"INTEGER\", \"TEXT\", \"INTEGER\"]\n\n// Get actual types from values\nconsole.log(stmt.columnTypes); // [\"integer\", \"text\", \"integer\"]\n\nconst row = stmt.get();\n```\n\nThe `declaredTypes`\n\narray shows the types as defined in your `CREATE TABLE`\n\nstatement, while `columnTypes`\n\nshows the actual SQLite storage class of the values returned.\n\n[Built-in Redis Client](#built-in-redis-client)\n\nRedis is a widely-used in-memory database, cache, and message broker and in Bun 1.3 introduces first-class support for Redis (and Valkey -- its BSD-licensed fork) and it's incredibly fast.\n\n``` js\nimport { redis, RedisClient } from \"bun\";\n\n// Connects to process.env.REDIS_URL or localhost:6379 if not set.\nawait redis.set(\"foo\", \"bar\");\nconst value = await redis.get(\"foo\");\nconsole.log(value); // \"bar\"\n\nconsole.log(await redis.ttl(\"foo\")); // -1 (no expiration set)\n```\n\nAll standard operations are supported, including hashes (`HSET`\n\n/`HGET`\n\n), lists (`LPUSH`\n\n/`LRANGE`\n\n) and sets -- totaling 66 commands. With automatic reconnects, command timeouts and message queuing, the Redis client handles high throughput and recovers from network failures.\n\nPub/Sub messaging is fully supported:\n\n``` js\nimport { RedisClient } from \"bun\";\n\n// You can create your own client instead of using `redis`.\nconst myRedis = new RedisClient(\"redis://localhost:6379\");\n\n// Subscribers can't publish, so duplicate the connection.\nconst publisher = await myRedis.duplicate();\n\nawait myRedis.subscribe(\"notifications\", (message, channel) => {\n  console.log(\"Received:\", message);\n});\n\nawait publisher.publish(\"notifications\", \"Hello from Bun!\");\n```\n\nBun's Redis client is significantly faster than `ioredis`\n\n, with the advantage increasing as batch size grows.\n\nSupport for clusters, streams and Lua scripting is in the works.\n\nSee the [Bun Redis documentation](https://bun.com/docs/api/redis) for more details and examples.\n\n[WebSocket Improvements](#websocket-improvements)\n\nBun 1.3 brings improvements to WebSocket support, making the implementation more compliant with web standards and adding powerful new capabilities.\n\n**RFC 6455 Compliant Subprotocol Negotiation**\n\nWebSocket clients now properly implement RFC 6455 compliant subprotocol negotiation. When you create a WebSocket connection, you can specify an array of subprotocols you'd like to use:\n\n``` js\nconst ws = new WebSocket(\"ws://localhost:3000\", [\"chat\", \"superchat\"]);\n\nws.onopen = () => {\n  console.log(`Connected with protocol: ${ws.protocol}`); // \"chat\"\n};\n```\n\nThe `ws.protocol`\n\nproperty is now properly populated with the server's selected subprotocol.\n\n**Override Special WebSocket Headers**\n\nBun 1.3 now allows you to override special WebSocket headers when creating a connection:\n\n``` js\nconst ws = new WebSocket(\"ws://localhost:8080\", {\n  headers: {\n    \"Host\": \"custom-host.example.com\",\n    \"Sec-WebSocket-Key\": \"dGhlIHNhbXBsZSBub25jZQ==\",\n  },\n});\n```\n\nThis is particularly useful using WebSocket clients that are proxied.\n\n**Automatic permessage-deflate Compression**\n\nBun 1.3 now automatically negotiates and enables `permessage-deflate`\n\ncompression when connecting to WebSocket servers that support it. This happens transparently—compression and decompression are handled automatically.\n\n``` js\nconst ws = new WebSocket(\"wss://echo.websocket.org\");\n\nws.onopen = () => {\n  console.log(\"Extensions:\", ws.extensions);\n  // \"permessage-deflate\"\n};\n```\n\nThis feature is enabled by default and will be automatically negotiated with servers that support it. Bun's builtin WebSocket server supports permessage-deflate compression. For applications that send repetitive or structured data like JSON, `permessage-deflate`\n\ncan reduce message sizes by 60-80% or more.\n\n[S3 improvements](#s3-improvements)\n\nBun's S3 client gets additional features:\n\n: ListObjectsV2 support for listing objects in a bucket`S3Client.list()`\n\n**Storage class support**: Specify`storageClass`\n\noption for S3 operations like`STANDARD_IA`\n\nor`GLACIER`\n\n``` js\nimport { s3 } from \"bun\";\n\n// List objects\nconst objects = await s3.list({ prefix: \"uploads/\" });\nfor (const obj of objects) {\n  console.log(obj.key, obj.size);\n}\n\n// Upload with storage class\nawait s3.file(\"archive.zip\").write(data, {\n  storageClass: \"GLACIER\",\n});\n\n// Use virtual hosted-style URLs (bucket in hostname)\nconst s3VirtualHosted = new S3Client({\n  virtualHostedStyle: true,\n});\n// Requests go to https://bucket-name.s3.region.amazonaws.com\n// instead of https://s3.region.amazonaws.com/bucket-name\n```\n\n[Bundler & Build](#bundler-build)\n\nBun's bundler adds programmatic compilation, cross-platform builds, and smarter minification in 1.3.\n\n[Create executables with the Bun.build() API](#create-executables-with-the-bun-build-api)\n\nCreate standalone executables programmatically with the `Bun.build()`\n\nAPI. This was previously only possible with the `bun build`\n\nCLI command.\n\n``` js\nimport { build } from \"bun\";\n\nawait build({\n  entrypoints: [\"./app.ts\"],\n  compile: true,\n  outfile: \"myapp\",\n});\n```\n\nThis produces a standalone executable without needing the CLI.\n\n[Code signing support](#code-signing-support)\n\nBun now supports code signing for Windows and macOS executables:\n\n**Windows**: Authenticode signature stripping for post-build signing** macOS**: Code signing for standalone executables\n\n```\n# macOS\nbun build --compile ./app.ts --outfile myapp\ncodesign --sign \"Developer ID\" ./myapp\n# Windows\nbun build --compile ./app.ts --outfile myapp.exe\nsigntool sign /f certificate.pfx myapp.exe\n```\n\n[Cross-compile executables](#cross-compile-executables)\n\nBuild executables for different operating systems and architectures.\n\n```\nbun build --compile --target=bun-linux-x64 ./app.ts --outfile myapp-linux\nbun build --compile --target=bun-darwin-arm64 ./app.ts --outfile myapp-macos\nbun build --compile --target=bun-windows-x64 ./app.ts --outfile myapp.exe\n```\n\nThis lets you build for Windows, macOS, and Linux from any platform.\n\n[Windows executable metadata](#windows-executable-metadata)\n\nSet executable metadata on Windows builds with `--title`\n\n, `--publisher`\n\n, `--version`\n\n, `--description`\n\n, and `--copyright`\n\n.\n\n```\nbun build --compile --target=bun-windows-x64 \\\\\n  --title=\"My App\" \\\\\n  --publisher=\"My Company\" \\\\\n  --version=\"1.0.0\" \\\\\n  ./app.ts\n```\n\n[Minification improvements](#minification-improvements)\n\nBun's minifier is even smarter in 1.3:\n\n- Remove unused function and class names (override with\n`-keep-names`\n\n) - Optimize\n`new Object()`\n\n,`new Array()`\n\n,`new Error()`\n\nexpressions - Minify\n`typeof undefined`\n\nchecks - Remove unused\n`Symbol.for()`\n\ncalls - Eliminate dead\n`try...catch...finally`\n\nblocks\n\n```\nbun build ./app.ts --minify\n```\n\n[JSX configuration](#jsx-configuration)\n\nConfigure JSX transformation in `Bun.build()`\n\nwith a centralized `jsx`\n\nobject.\n\n```\nawait build({\n  entrypoints: [\"./app.tsx\"],\n  jsx: {\n    factory: \"h\",\n    fragment: \"Fragment\",\n    importSource: \"preact\",\n  },\n});\n```\n\n[Other bundler improvements](#other-bundler-improvements)\n\n: Preserve JSX with side effects during tree-shaking`jsxSideEffects`\n\noption: Plugin hook that runs after build completion`onEnd`\n\nhook**Glob patterns in sideEffects**:`package.json`\n\nsupports glob patterns like`\"sideEffects\": [\"*.css\"]`\n\n**Top-level await improvements**: Better handling of cyclic dependencies: Embed runtime flags into executables`-compile-exec-argv`\n\n[Package Management](#package-management)\n\nBun's package manager gets more powerful with isolated installs, interactive updates, dependency catalogs, and security auditing.\n\n[Catalogs synchronize dependency versions](#catalogs-synchronize-dependency-versions)\n\nBun 1.3 makes it easier to work with monorepos.\n\nBun centralizes version management across monorepo packages with dependency `catalogs`\n\n. Define versions once in your root `package.json`\n\nand reference them in workspace packages.\n\n```\n{\n  \"name\": \"monorepo\",\n  \"workspaces\": [\"packages/*\"],\n  \"catalog\": {\n    \"react\": \"^18.0.0\",\n    \"typescript\": \"^5.0.0\"\n  }\n}\n```\n\nReference catalog versions in workspace packages:\n\n```\n{\n  \"name\": \"@company/ui\",\n  \"dependencies\": {\n    \"react\": \"catalog:\"\n  }\n}\n```\n\nNow all packages use the same version of React. Update the catalog once to update everywhere. This is inspired by [pnpm's catalog feature](https://pnpm.io/catalogs).\n\n[Isolated installs are now the default for workspaces](#isolated-installs-are-now-the-default-for-workspaces)\n\nBun 1.3 introduces [isolated installs](/docs/install/isolated). This prevents packages from accessing dependencies they don't declare in their `package.json`\n\n, addressing the #1 issue users faced with Bun in large monorepos. Unlike hoisted installs (npm/Yarn's flat structure where all dependencies live in a single `node_modules`\n\n), isolated installs ensure each package only has access to its own declared dependencies.\n\nAnd if you use `\"workspaces\"`\n\nin your `package.json`\n\n, we're making it the default behavior.\n\nTo opt out do one of the folowing:\n\n```\nbun install --linker=hoisted\n[install]\nlinker = \"hoisted\"\n```\n\n[pnpm.lock & yarn.lock migration support](#pnpm-lock-yarn-lock-migration-support)\n\nIn Bun 1.3, we’ve expanded automatic lockfile conversion to support migrating from yarn (`yarn.lock`\n\n) and pnpm (`pnpm-lock.yaml`\n\n) to Bun’s lockfile. Your dependency tree stays the same, and Bun preserves the resolved versions from your original lockfile. You can commit the new lockfile to your repository without any surprises. This makes it easy to try `bun install`\n\nat work without asking your team to upgrade to Bun.\n\n[Security Scanner API](#security-scanner-api)\n\nBun 1.3 introduces the Security Scanner API, enabling you to scan packages for vulnerabilities before installation. Security scanners analyze packages during `bun install`\n\n, `bun add`\n\n, and other package operations to detect known CVEs, malicious packages, and license compliance issues. We're excited to be working with [Socket](https://socket.dev/) to launch with their [official security scanner: @socketsecurity/bun-security-scanner](https://www.npmjs.com/package/@socketsecurity/bun-security-scanner).\n\n*“We’re excited to see the Bun team moving so quickly to protect developers at the package manager level. By opening up the Security Scanner API, they’ve made it possible for tools like Socket to deliver real-time threat detection directly in the install process. It’s a great step forward for making open source development safer by default.”*\n\n— Ahmad Nassri, CTO of Socket\n\n**Configure a security scanner in bunfig.toml:**\n\nMany security companies publish Bun security scanners as npm packages.\n\n```\nbun add -d @acme/bun-security-scanner # This is an example\n```\n\nNext, configure in your `bunfig.toml`\n\n:\n\n```\n[install.security]\nscanner = \"@acme/bun-security-scanner\"\n```\n\nNow, Bun will scan all packages before installation, display security warnings, and cancel installation if critical advisories are found.\n\n**Scanners report issues at two severity levels:**\n\n`fatal`\n\n: Installation stops immediately, exits with non-zero code`warn`\n\n— In interactive terminals, prompts to continue; in CI, exits immediately\n\nEnterprise scanners may support authentication through environment variables:\n\n```\nexport SECURITY_API_KEY=\"your-api-key\"\nbun install # Scanner uses credentials automatically\n```\n\nFor teams with specific security requirements, you can build custom security scanners. See the [official template](https://github.com/oven-sh/security-scanner-template) for a complete example with tests and CI setup.\n\n[Minimum release age](#minimum-release-age)\n\nIn Bun 1.3, you can protect yourself against supply chain attacks by requiring packages to be published for a minimum time before installation.\n\n```\n[install]\nminimumReleaseAge = 604800 # 7 days in seconds\n```\n\nThis prevents installing packages that were just published, giving the community time to identify malicious packages before they reach your codebase.\n\n[Platform-specific dependencies](#platform-specific-dependencies)\n\nControl which platform-specific `optionalDependencies`\n\ninstall with `--cpu`\n\nand `--os`\n\nflags:\n\n```\n# Linux ARM64\nbun install --os linux --cpu arm64\n# Multiple platforms\nbun install --os darwin --os linux --cpu x64\n# All platforms\nbun install --os '*' --cpu '*'\n```\n\n[Workspace configuration](#workspace-configuration)\n\nControl workspace package linking behavior with `linkWorkspacePackages`\n\n:\n\n```\n[install]\nlinkWorkspacePackages = false\n```\n\nWhen `false`\n\n, Bun installs workspace dependencies from the registry instead of linking locally—useful in CI where pre-built packages are faster than building from source.\n\n[New commands](#new-commands)\n\nBun 1.3 adds several commands that make package management easier:\n\n** bun why** explains why a package is installed:\n\n```\nbun why tailwindcss\n[0.05ms] \".env\"\ntailwindcss@3.4.17\n  └─ peer @tailwindcss/typography@0.5.16 (requires >=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1)\n\ntailwindcss@3.3.2\n  └─ tw-to-css@0.0.12 (requires 3.3.2)\n```\n\nIt shows you the full dependency chain: *which* of your dependencies depends on tailwindcss, and *why* it's in your `node_modules`\n\n. This is especially useful when you're trying to figure out why a package you didn't explicitly install is showing up in your project.\n\n** bun update --interactive** lets you choose which dependencies to update:\n\n```\nbun update --interactive\ndependencies                             Current        Target   Latest\n  ❯ □ @tailwindcss/typography              0.5.16         0.5.19   0.5.19\n    □ lucide-react                         0.473.0        0.473.0  0.544.0\n    □ prettier                             2.8.8          2.8.8    3.6.2\n    □ prettier-plugin-tailwindcss          0.2.8          0.2.8    0.6.14\n    □ react                                18.3.1         18.3.1   19.1.1\n    □ react-dom                            18.3.1         18.3.1   19.1.1\n    □ satori                               0.12.2         0.12.2   0.18.3\n    □ semver                               7.7.0          7.7.2    7.7.2\n    □ shiki                                0.10.1         0.10.1   3.13.0\n    □ tailwindcss                          3.4.17         3.4.18   4.1.14\n    □ zod                                  3.24.1         3.25.76  4.1.11\n```\n\nInstead of updating everything at once, you can scroll through your dependencies and select which ones to update. This gives you control over breaking changes. You can update your test framework separately from your production dependencies, or update one major version at a time.\n\nIn monorepos, you can scope updates to specific workspaces with the `--filter`\n\nflag:\n\n```\n# Update dependencies only in the @myapp/frontend workspace\nbun update -i --filter @myapp/frontend\n# Update multiple workspaces\nbun update -i --filter @myapp/frontend --filter @myapp/backend\n```\n\nYou can also run commands recursively across all workspace packages:\n\n```\nbun outdated --recursive    # Check all workspaces\n┌─────────────────────────────┬─────────┬─────────┬─────────┬───────────┐\n│ Package                     │ Current │ Update  │ Latest  │ Workspace │\n├─────────────────────────────┼─────────┼─────────┼─────────┼───────────┤\n│ @tailwindcss/typography     │ 0.5.16  │ 0.5.19  │ 0.5.19  │           │\n├─────────────────────────────┼─────────┼─────────┼─────────┼───────────┤\n│ lucide-react                │ 0.473.0 │ 0.473.0 │ 0.544.0 │           │\n├─────────────────────────────┼─────────┼─────────┼─────────┼───────────┤\n│ prettier                    │ 2.8.8   │ 2.8.8   │ 3.6.2   │ catalog:  │\n├─────────────────────────────┼─────────┼─────────┼─────────┼───────────┤\n│ prettier-plugin-tailwindcss │ 0.2.8   │ 0.2.8   │ 0.6.14  │           │\n├─────────────────────────────┼─────────┼─────────┼─────────┼───────────┤\n│ react                       │ 18.3.1  │ 18.3.1  │ 19.1.1  │ my-app    │\n├─────────────────────────────┼─────────┼─────────┼─────────┼───────────┤\n│ react-dom                   │ 18.3.1  │ 18.3.1  │ 19.1.1  │ my-app    │\n├─────────────────────────────┼─────────┼─────────┼─────────┼───────────┤\n│ satori                      │ 0.12.2  │ 0.12.2  │ 0.18.3  │           │\n├─────────────────────────────┼─────────┼─────────┼─────────┼───────────┤\n│ semver                      │ 7.7.0   │ 7.7.2   │ 7.7.2   │           │\n├─────────────────────────────┼─────────┼─────────┼─────────┼───────────┤\n│ shiki                       │ 0.10.1  │ 0.10.1  │ 3.13.0  │           │\n├─────────────────────────────┼─────────┼─────────┼─────────┼───────────┤\n│ tailwindcss                 │ 3.4.17  │ 3.4.18  │ 4.1.14  │           │\n├─────────────────────────────┼─────────┼─────────┼─────────┼───────────┤\n│ zod                         │ 3.24.1  │ 3.25.76 │ 4.1.11  │           │\n└─────────────────────────────┴─────────┴─────────┴─────────┴───────────┘\n```\n\nThe **Workspace** column shows which workspace package each dependency belongs to, making it easy to track dependencies across your monorepo. When using `bun update -i`\n\n, this column helps you understand the scope of your updates.\n\nBoth `bun outdated`\n\nand `bun update -i`\n\nnow fully support catalog dependencies defined in your root `package.json`\n\n, so you can see and update catalog versions just like regular dependencies.\n\n```\nbun update -i --recursive  # Update all workspaces\n```\n\n`bun info`\n\nlets you view package metadata\n\n```\nbun info react\nreact@19.2.0 | MIT | deps: 0 | versions: 2536\nReact is a JavaScript library for building user interfaces.\nhttps://react.dev/\nkeywords: react\n\ndist\n .tarball: https://registry.npmjs.org/react/-/react-19.2.0.tgz\n .shasum: d33dd1721698f4376ae57a54098cb47fc75d93a5\n .integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==\n .unpackedSize: 171.60 KB\n\ndist-tags:\nbeta: 19.0.0-beta-26f2496093-20240514\nrc: 19.0.0-rc.1\nlatest: 19.2.0\nnext: 19.3.0-canary-4fdf7cf2-20251003\ncanary: 19.3.0-canary-4fdf7cf2-20251003\nexperimental: 0.0.0-experimental-4fdf7cf2-20251003\n\nmaintainers:\n- fb <opensource+npm@fb.com>\n- react-bot <react-core@meta.com>\n\nPublished: 2025-10-01T21:38:32.757Z\n```\n\nThis shows package versions, dependencies, dist-tags, and more. This is useful for quickly checking what's available before installing.\n\n`bun install --analyze`\n\nlets you scans your code for imports that aren't in `package.json`\n\nand installs them. This is useful when you've added imports but forgot to install the packages.\n\n```\nbun install --analyze\n```\n\n`bun audit`\n\nscans dependencies for known vulnerabilities using the same database as `npm audit`\n\n```\nbun audit\nbun audit --severity=high\nbun audit --json > report.json\n```\n\n[Other package manager improvements](#other-package-manager-improvements)\n\n: Bump package.json versions with pre/post version scripts`bun pm version`\n\n: Edit package.json with`bun pm pkg`\n\n`get`\n\n,`set`\n\n,`delete`\n\n, and`fix`\n\ncommands**Platform filtering**: Use`--cpu`\n\nand`--os`\n\nflags to filter optional dependencies by platform**Quiet pack mode**: Use`bun pm pack --quiet`\n\nfor scripting**Custom pack output**: Use`bun pm pack --filename <path>`\n\nto specify the output tarball name and location`bun install --lockfile-only`\n\nhas been optimized to only fetch package manifests, not tarballs\n\n```\n# Create tarball with custom name and location\nbun pm pack --filename ./dist/my-package-1.0.0.tgz\n```\n\n[Testing and Debugging Improvements](#testing-and-debugging-improvements)\n\nBun's test runner gets more powerful with VS Code integration, concurrent tests, type testing, and better output.\n\n[Async Stack Traces](#async-stack-traces)\n\nWe've worked closely with WebKit to add support for richer async stack traces in JavaScriptCore. Previously, errors in async functions failed to preserve the async call trace. For example:\n\n```\nasync function foo() {\n  return await bar();\n}\n\nasync function bar() {\n  return await baz();\n}\n\nasync function baz() {\n  await 1; // ensure it's a real async function\n  throw new Error(\"oops\");\n}\n\ntry {\n  await foo();\n} catch (e) {\n  console.log(e);\n}\n```\n\nIn Bun 1.3, this now outputs:\n\n```\n❯ bun async.js\n 6 |   return await baz();\n 7 | }\n 8 |\n 9 | async function baz() {\n10 |   await 1; // ensure it's a real async function\n11 |   throw new Error(\"oops\");\n             ^\nerror: oops\n      at baz (async.js:11:9)\n      at async bar (async.js:6:16)\n      at async foo (async.js:2:16)\n```\n\nThis feature also benefits Safari and other JavaScriptCore-based runtimes.\n\n💡 Read more about the [technical challenges of implementing async stack traces](https://docs.google.com/document/d/13Sy_kBIJGP0XT34V1CV3nkWya4TwYx9L3Yv45LdGB6Q/edit?usp=sharing).\n\n[VS Code Test Explorer integration](#vs-code-test-explorer-integration)\n\nBun's test runner now integrates with VS Code's Test Explorer UI. Tests appear in the sidebar, and you can run, debug, and view results without leaving your editor. Run individual tests with one click and see inline error messages directly in your code.\n\nInstall the [Bun for Visual Studio Code extension](https://marketplace.visualstudio.com/items?itemName=oven.bun-vscode) to get started.\n\n[Concurrent testing with bun:test](#concurrent-testing-with-bun-test)\n\n`bun test`\n\nnow supports running multiple asynchronous tests 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 } from \"bun:test\";\n\ntest.concurrent(\"fetch user 1\", async () => {\n  const res = await fetch(\"https://api.example.com/users/1\");\n  expect(res.status).toBe(200);\n});\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\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\n`test.serial`\n\nto make specific tests sequentialWhen 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[Randomize test order with ](#randomize-test-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[Chain qualifiers](#chain-qualifiers)\n\nYou 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[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\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 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[Mark tests as expected to fail](#mark-tests-as-expected-to-fail)\n\nUse `test.failing()`\n\nto mark tests that are expected to fail. This is useful for documenting known bugs or practicing Test-Driven Development (TDD) where you write the test before the implementation:\n\n``` js\nimport { test, expect } from \"bun:test\";\n\ntest.failing(\"known bug: division by zero\", () => {\n  expect(divide(10, 0)).toBe(Infinity);\n  // This test currently fails but is expected to fail\n  // Remove .failing when the bug is fixed\n});\n\ntest.failing(\"TDD: feature not yet implemented\", () => {\n  expect(newFeature()).toBe(\"working\");\n  // Remove .failing once you implement newFeature()\n});\n```\n\nWhen a `test.failing()`\n\ntest passes, Bun reports it as a failure (since you expected it to fail). This helps you remember to remove the `.failing`\n\nmodifier once you fix the bug or implement the feature.\n\n[Type testing with ](#type-testing-with-expecttypeof)`expectTypeOf()`\n\n`expectTypeOf()`\n\nTest TypeScript types alongside unit tests using `expectTypeOf()`\n\n. These assertions can be checked by the TypeScript compiler:\n\n``` js\nimport { expectTypeOf, test } from \"bun:test\";\n\ntest(\"types are correct\", () => {\n  expectTypeOf<string>().toEqualTypeOf<string>();\n  expectTypeOf({ foo: 1 }).toHaveProperty(\"foo\");\n  expectTypeOf<Promise<number>>().resolves.toBeNumber();\n});\n```\n\nVerify type tests by running `bunx tsc --noEmit`\n\n.\n\n[New matchers](#new-matchers)\n\nBun 1.3 adds new matchers for testing return values:\n\n`toHaveReturnedWith(value)`\n\n: Check if a mock returned a specific value`toHaveLastReturnedWith(value)`\n\n: Check the last return value`toHaveNthReturnedWith(n, value)`\n\n: Check the nth return value\n\n``` js\nimport { test, expect, mock } from \"bun:test\";\n\ntest(\"mock return values\", () => {\n  const fn = mock(() => 42);\n  fn();\n  fn();\n\n  expect(fn).toHaveReturnedWith(42);\n  expect(fn).toHaveLastReturnedWith(42);\n  expect(fn).toHaveNthReturnedWith(1, 42);\n});\n```\n\n[Indented inline snapshots](#indented-inline-snapshots)\n\nInline snapshots now support automatic indentation detection and preservation, matching Jest's behavior. When you use `.toMatchInlineSnapshot()`\n\n, Bun automatically formats the snapshot to match your code's indentation level:\n\n``` js\nimport { test, expect } from \"bun:test\";\n\ntest(\"formats user data\", () => {\n  const user = { name: \"Alice\", age: 30, email: \"alice@example.com\" };\n\n  expect(user).toMatchInlineSnapshot(`\n    {\n      \"name\": \"Alice\",\n      \"age\": 30,\n      \"email\": \"alice@example.com\",\n    }\n  `);\n});\n```\n\nThe snapshot content is automatically indented to align with your test code, making snapshots more readable and easier to maintain.\n\n[Other testing improvements](#other-testing-improvements)\n\n: Clear all mocks at once`mock.clearAllMocks()`\n\n**Coverage filtering**: Use`test.coveragePathIgnorePatterns`\n\nto exclude paths from coverage**Variable substitution**: Use`$variable`\n\nand`$object.property`\n\nin`test.each`\n\ntitles**Improved diffs** Better visualization with whitespace highlighting**Stricter CI mode**: Errors on`test.only()`\n\nand new snapshots without`--update-snapshots`\n\n**Compact AI output**: Condensed output for AI coding assistants\n\n[APIs & Standards](#apis-standards)\n\nBun 1.3 expands support for modern web standards and APIs, making it easier to build applications that work across different JavaScript environments.\n\n[YAML Support](#yaml-support)\n\nIn Bun 1.3, you can parse and stringify YAML directly with `Bun.YAML`\n\n.\n\n``` js\nimport { YAML } from \"bun\";\n\nconst obj = YAML.parse(\"key: value\");\nconsole.log(obj); // { key: \"value\" }\n\nconst yaml = YAML.stringify({ key: \"value\" }, 0, 2);\nconsole.log(yaml); // \"key: value\"\n```\n\nYou can also import YAML files directly:\n\n``` python\nimport config from \"./config.yaml\";\nconsole.log(config);\n```\n\nThe parser powering YAML in Bun is written from scratch and currently passes 90% of the official [yaml-test-suite](https://github.com/yaml/yaml-test-suite). It supports all features except for literal chomping (`|+`\n\nand `|-`\n\n) and cyclic references. In the near future we will get it to 100% passing.\n\n[Cookies](#cookies)\n\nMost production web applications read and write cookies. Usually in server-side JavaScript, you must choose either a single-purpose cookie parsing library like `tough-cookie`\n\n, or adopting a web framework like Express or Elysia. Cookie parsing & serialization is a well-understood problem.\n\nBun 1.3 simplifies this. Bun's HTTP server now includes built-in cookie support with a powerful, Map-like API. The new `request.cookies`\n\nAPI automatically detects when you make changes to cookies and intelligently adds the appropriate `Set-Cookie`\n\nheaders to your response.\n\n``` js\nimport { serve, randomUUIDv7 } from \"bun\";\n\nserve({\n  routes: {\n    \"/api/users/sign-in\": (request) => {\n      request.cookies.set(\"sessionId\", randomUUIDv7(), {\n        httpOnly: true,\n        sameSite: \"strict\",\n      });\n      return new Response(\"Signed in\");\n    },\n    \"/api/users/sign-out\": (request) => {\n      request.cookies.delete(\"sessionId\");\n      return new Response(\"Signed out\");\n    },\n  },\n});\n```\n\nWhen you call `request.cookies.set()`\n\n, Bun adds the appropriate `Set-Cookie`\n\nheader to your response. When you call `request.cookies.delete()`\n\n, it generates the correct header to tell the browser to remove that cookie.\n\nOne key design principle is that this API has zero performance overhead when you're not using cookies. The `Cookie`\n\nheader from incoming requests isn't parsed until the moment you access `request.cookies`\n\n.\n\nYou have full control over all standard cookie attributes:\n\n```\nrequest.cookies.set(\"preferences\", JSON.stringify(userPrefs), {\n  httpOnly: false, // Allow JavaScript access\n  secure: true, // Only send over HTTPS\n  sameSite: \"lax\", // Allow some cross-site requests\n  maxAge: 60 * 60 * 24 * 365, // 1 year in seconds\n  path: \"/\", // Available on all paths\n  domain: \".example.com\", // Available on all subdomains\n});\n```\n\nYou can also read and write cookies outside of Bun.serve() using the `Bun.Cookie`\n\nand `Bun.CookieMap`\n\nclasses.\n\n``` js\nconst cookie = new Bun.Cookie(\"sessionId\", \"123\");\ncookie.value = \"456\";\nconsole.log(cookie.value); // \"456\"\nconsole.log(cookie.serialize()); // \"sessionId=456; Path=/; SameSite=lax\"\n\nconst cookieMap = new Bun.CookieMap(\"sessionId=321; token=aaaa\");\nconsole.log(cookieMap.get(\"sessionId\")); // 321\nconsole.log(cookieMap.get(\"token\")); // aaaa\ncookieMap.set(\"user1\", \"hello\");\ncookieMap.set(\"user2\", \"world\");\nconsole.log(cookieMap.toSetCookieHeaders());\n// => [ \"user1=hello; Path=/; SameSite=Lax\", \"user2=world; Path=/; SameSite=Lax\" ]\n```\n\n[Consume a ReadableStream with convenience methods](#consume-a-readablestream-with-convenience-methods)\n\nConsume `ReadableStream`\n\ns directly with helpful `.text()`\n\n, `.json()`\n\n, `.bytes()`\n\n, and `.blob()`\n\nmethods.\n\n``` js\nconst stream = new ReadableStream({\n  start(controller) {\n    controller.enqueue(new TextEncoder().encode(\"Hello\"));\n    controller.close();\n  },\n});\n\nconst text = await stream.text(); // \"Hello\"\n```\n\nThis matches the upcoming Web Streams standard and makes it easier to work with streams.\n\n[WebSocket improvements](#websocket-improvements)\n\n**Compression**: Client-side`permessage-deflate`\n\nsupport for reduced bandwidth**Subprotocol negotiation**: RFC 6455 compliant protocol negotiation** Header overrides**: Override`Host`\n\n,`Sec-WebSocket-Key`\n\n, and other headers\n\n``` js\nconst ws = new WebSocket(\"wss://example.com\", {\n  headers: {\n    \"User-Agent\": \"MyApp/1.0\",\n  },\n  perMessageDeflate: true,\n});\n```\n\n[WebAssembly streaming](#webassembly-streaming)\n\nCompile and instantiate WebAssembly modules from streams with `WebAssembly.compileStreaming()`\n\nand `instantiateStreaming()`\n\n.\n\n``` js\nconst response = fetch(\"module.wasm\");\nconst module = await WebAssembly.compileStreaming(response);\nconst instance = await WebAssembly.instantiate(module);\n```\n\nThis is more efficient than loading the entire WASM file into memory first.\n\n[Zstandard compression](#zstandard-compression)\n\nBun 1.3 adds full support for Zstandard (zstd) compression, including automatic decompression of HTTP responses and manual compression APIs.\n\n**Automatic decompression in fetch().** When a server sends a response with\n\n`Content-Encoding: zstd`\n\n, Bun automatically decompresses it:\n\n``` js\n// Server sends zstd-compressed response\nconst response = await fetch(\"https://api.example.com/data\");\nconst data = await response.json(); // Automatically decompressed\n```\n\n**Manual compression and decompression.** Use Bun's APIs or the `node:zlib`\n\nmodule for direct compression:\n\n``` js\nimport { zstdCompressSync, zstdDecompressSync } from \"node:zlib\";\n\nconst compressed = zstdCompressSync(\"Hello, world!\");\nconst decompressed = zstdDecompressSync(compressed);\nconsole.log(decompressed.toString()); // \"Hello, world!\"\n\n// Or use Bun's async APIs\nimport { zstdCompress, zstdDecompress } from \"bun\";\nconst compressed2 = await zstdCompress(\"Hello, world!\");\nconst decompressed2 = await zstdDecompress(compressed2);\n```\n\n[DisposableStack and AsyncDisposableStack](#disposablestack-and-asyncdisposablestack)\n\nBun 1.3 implements `DisposableStack`\n\nand `AsyncDisposableStack`\n\nfrom the TC39 Explicit Resource Management proposal. These stack-based containers help manage disposable resources that use the `using`\n\nand `await using`\n\ndeclarations.\n\n``` js\nconst stack = new DisposableStack();\n\nstack.use({\n  [Symbol.dispose]() {\n    console.log(\"Cleanup!\");\n  },\n});\n\n// Dispose all resources at once\nstack.dispose(); // \"Cleanup!\"\n```\n\n`DisposableStack`\n\naggregates multiple disposable resources into a single container, ensuring all resources are properly cleaned up when the stack is disposed. `AsyncDisposableStack`\n\nprovides the same functionality for asynchronous cleanup with `Symbol.asyncDispose`\n\n. If any resource throws during disposal, the error is collected and rethrown after all resources are disposed.\n\n[Security Enhancements](#security-enhancements)\n\n[Bun.secrets for Encrypted Credential Storage](#bun-secrets-for-encrypted-credential-storage)\n\nBun 1.3 introduces the `Bun.secrets`\n\nAPI, allowing you to use your OS's native credential storage:\n\n``` js\nimport { secrets } from \"bun\";\n\nawait secrets.set({\n  service: \"my-app\",\n  name: \"api-key\",\n  value: \"secret-value\",\n});\nconst key: string | null = await secrets.get({\n  service: \"my-app\",\n  name: \"api-key\",\n});\n```\n\nSecrets are stored in Keychain on macOS, libsecret on Linux, and Windows Credential Manager on Windows. They're encrypted at rest and separate from environment variables.\n\n[CSRF Protection](#csrf-protection)\n\nBun 1.3 adds `Bun.CSRF`\n\nfor cross-site request forgery protection by letting you generate and verify XSRF/CSRF tokens.\n\n``` js\nimport { CSRF } from \"bun\";\n\nconst secret = \"your-secret-key\";\nconst token = CSRF.generate({ secret, encoding: \"hex\", expiresIn: 60 * 1000 });\nconst isValid = CSRF.verify(token, { secret });\n```\n\n[Crypto performance improvements](#crypto-performance-improvements)\n\nBun 1.3 includes major performance improvements to Node.js crypto APIs:\n\n**DiffieHellman**: ~400x faster** Cipheriv/Decipheriv**: ~400x faster** scrypt**: ~6x faster\n\nThese improvements make cryptographic operations significantly faster for password hashing, encryption, and key derivation.\n\n```\nclk: ~4.74 GHz\ncpu: AMD Ryzen AI 9 HX 370 w/ Radeon 890M\nruntime: bun 1.3.0 (x64-linux)\n\nbenchmark                            avg (min … max)\n----------------------------------------------------\ncreateDiffieHellman - 512             103.90 ms/iter\n                              (39.30 ms … 237.74 ms)\n\nCipheriv and Decipheriv - aes-256-gcm   2.25 µs/iter\n                                 (1.90 µs … 2.63 µs)\n\nscrypt - N=16384, p=1, r=1             36.94 ms/iter\n                               (35.98 ms … 38.04 ms)\nclk: ~4.86 GHz\ncpu: AMD Ryzen AI 9 HX 370 w/ Radeon 890M\nruntime: bun 1.2.0 (x64-linux)\n\nbenchmark                            avg (min … max)\n----------------------------------------------------\ncreateDiffieHellman - 512               41.15 s/iter\n                              (366.85 ms … 136.49 s)\n\nCipheriv and Decipheriv - aes-256-gcm 912.65 µs/iter\n                               (804.29 µs … 6.12 ms)\n\nscrypt - N=16384, p=1, r=1            224.92 ms/iter\n                             (222.30 ms … 232.52 ms)\n```\n\nOther crypto improvements:\n\n**X25519 curve**: Elliptic curve support in`crypto.generateKeyPair()`\n\n**HKDF**:`crypto.hkdf()`\n\nand`crypto.hkdfSync()`\n\nfor key derivation**Prime number functions**:`crypto.generatePrime()`\n\n,`crypto.checkPrime()`\n\nand sync variants**System CA certificates**:`--use-system-ca`\n\nflag to use OS trusted certificates: Full implementation with`crypto.KeyObject`\n\nhierarchy`structuredClone`\n\nsupport\n\n[Node.js compatibility](#node-js-compatibility)\n\nBun now runs 800 more tests from the Node.js test suite on every commit of Bun. We're continuing making progress toward full Node.js compatibility. In Bun 1.3, we've added support for the VM module, `node:test`\n\n, performance monitoring, and more.\n\n[Worker enhancements](#worker-enhancements)\n\nWe made Bun's `worker_threads`\n\nimplementation more compatible with Node.js. You can use the `getEnvironmentData`\n\nand `setEnvironmentData`\n\nmethods to share data between parent threads and workers with the `environmentData`\n\nAPI:\n\n``` js\n// Share data between workers with environmentData\nimport {\n  Worker,\n  getEnvironmentData,\n  setEnvironmentData,\n} from \"node:worker_threads\";\n\n// Set data in parent thread\nsetEnvironmentData(\"config\", { timeout: 1000 });\n\n// Create a worker\nconst worker = new Worker(\"./worker.js\");\n\n// In worker.js:\nimport { getEnvironmentData } from \"node:worker_threads\";\nconst config = getEnvironmentData(\"config\");\nconsole.log(config.timeout); // 1000\njs\nimport { Worker, setEnvironmentData, getEnvironmentData } from \"worker_threads\";\n\nsetEnvironmentData(\"config\", { debug: true });\n\nconst worker = new Worker(\"./worker.js\");\n\n// In worker.js\nimport { getEnvironmentData } from \"worker_threads\";\nconst config = getEnvironmentData(\"config\");\nconsole.log(config.debug); // true\n```\n\n`node:test`\n\nsupport\n\n`node:test`\n\nsupportBun now includes initial support for the `node:test`\n\nmodule, leveraging `bun:test`\n\nunder the hood to provide a unified testing experience. This implementation allows you to run Node.js tests with the same performance benefits of Bun's native test runner.\n\n``` python\nimport { test, describe } from \"node:test\";\nimport assert from \"node:assert\";\n\ndescribe(\"Math\", () => {\n  test(\"addition\", () => {\n    assert.strictEqual(1 + 1, 2);\n  });\n});\n```\n\n`node:vm`\n\nimprovements\n\n`node:vm`\n\nimprovementsThe `node:vm`\n\nmodule gets major improvements in Bun 1.3:\n\n: Evaluate ECMAScript modules`vm.SourceTextModule`\n\n: Create synthetic modules`vm.SyntheticModule`\n\n: Compile JavaScript into functions`vm.compileFunction`\n\n: Use`vm.Script`\n\nbytecode caching`cachedData`\n\nfor faster compilation: Support for non-contextified values`vm.constants.DONT_CONTEXTIFY`\n\n``` python\nimport vm from \"node:vm\";\n\nconst script = new vm.Script('console.log(\"Hello from VM\")');\nscript.runInThisContext();\n```\n\nThese APIs enable advanced use cases like code evaluation sandboxes, plugin systems, and custom module loaders.\n\n`require.extensions`\n\n`require.extensions`\n\nBun now supports Node.js's [ require.extensions](https://nodejs.org/api/modules.html#requireextensions) API, allowing packages that rely on custom file loaders to work in Bun.\n\n``` js\nrequire.extensions[\".txt\"] = (module, filename) => {\n  const content = require(\"fs\").readFileSync(filename, \"utf8\");\n  module.exports = content;\n};\n\nconst text = require(\"./file.txt\");\nconsole.log(text); // File contents as string\n```\n\nThis is a legacy Node.js API that enables loading non-JavaScript files with `require()`\n\n. While we don't recommend using it in new code (use import attributes or loaders instead), supporting it ensures compatibility with existing packages in the npm ecosystem.\n\n[Disable Native Addons](#disable-native-addons)\n\nUse the `--no-addons`\n\nflag to disable Node.js native addons at runtime:\n\n```\nbun --no-addons ./app.ts\n```\n\nWhen disabled, attempts to load native addons will throw an `ERR_DLOPEN_DISABLED`\n\nerror. This is useful for security-sensitive environments where you want to ensure no native code can be loaded.\n\nBun also supports the `\"node-addons\"`\n\nexport condition in `package.json`\n\nfor conditional package resolution:\n\n```\n{\n  \"exports\": {\n    \".\": {\n      \"node-addons\": \"./native.node\",\n      \"default\": \"./fallback.js\"\n    }\n  }\n}\n```\n\n[Other Node.js compatibility improvements](#other-node-js-compatibility-improvements)\n\n#### Core Module Improvements\n\n** node:fs**:\n\n`fs.glob()`\n\n,`fs.globSync()`\n\n, and`fs.promises.glob()`\n\nwith array patterns and exclude options- Support for embedded files in Single-File Executables\n`fs.Stats`\n\nconstructor matches Node.js behavior (undefined values instead of zeros)`fs.fstatSync`\n\nbigint option support- EINTR handling in\n`fs.writeFile`\n\nand`fs.readFile`\n\nfor interrupted system calls `fs.watchFile`\n\nemits 'stop' event and ignores access time changes`fs.mkdirSync`\n\nWindows NT prefix support`fs.Dir`\n\nvalidation improvements`process.binding('fs')`\n\nimplementation\n\n** node:http and node:http2**:\n\n`http.Server.closeIdleConnections()`\n\nfor graceful shutdown`http.ClientRequest#flushHeaders`\n\ncorrectly sends request body- Array-based\n`Set-Cookie`\n\nheader format in`writeHead()`\n\n- CONNECT method support for HTTP proxies\n- Numeric header names support\n- WebSocket, CloseEvent, and MessageEvent exports from\n`node:http`\n\n- HTTP/2 stream management, response handling, and window size configuration improvements\n`maxSendHeaderBlockLength`\n\noption`setNextStreamID`\n\nsupport`remoteSettings`\n\nevent for default settings- Type validation for client request options\n`util.promisify(http2.connect)`\n\nsupport\n\n** node:net**:\n\n`net.BlockList`\n\nclass for IP address blocking`net.SocketAddress`\n\nclass with`parse()`\n\nmethod`AbortSignal`\n\nsupport in`net.createServer()`\n\nand`server.listen()`\n\n`resetAndDestroy()`\n\nmethod`server.maxConnections`\n\nsupport- Port as string support in\n`listen()`\n\n- Improved validation for\n`localAddress`\n\n,`localPort`\n\n,`keepAlive`\n\noptions - Major rework adding 43 new passing tests\n- Handle leak and connection management fixes\n`socket.write()`\n\naccepts Uint8Array\n\n** node:crypto**:\n\n- X25519 curve support in\n`crypto.generateKeyPair()`\n\n- Native C++ implementation of Sign and Verify classes (34x faster)\n- Native C++ implementation of Hash and Hmac classes\n`hkdf`\n\nand`hkdfSync`\n\nfor key derivation`generatePrime`\n\n,`generatePrimeSync`\n\n,`checkPrime`\n\n,`checkPrimeSync`\n\n- Native implementations: Cipheriv, Decipheriv, DiffieHellman, DiffieHellmanGroup, ECDH, randomFill(Sync), randomBytes\n- Full KeyObject class hierarchy with structuredClone support\n- Lowercase algorithm names support\n`crypto.verify()`\n\ndefaults to SHA256 for RSA keys`crypto.randomInt`\n\ncallback support\n\n** node:buffer**:\n\n- Resizable and growable shared ArrayBuffers\n`--zero-fill-buffers`\n\nflag support`Buffer.prototype.toLocaleString`\n\nalias`Buffer.prototype.inspect()`\n\nhexadecimal output`Buffer.isAscii()`\n\nfix`process.binding('buffer')`\n\nimplementation\n\n** node:process**:\n\n`process.stdin.ref()`\n\nand`process.stdin.unref()`\n\nfixes`process.stdout.write`\n\npreventing process exit fix`process.ref()`\n\nand`process.unref()`\n\nfor event loop control`process.emit('worker')`\n\nevent for worker creation`process._eval`\n\nproperty for`-e`\n\n/`--eval`\n\ncode`process.on('rejectionHandled')`\n\nevent support`--unhandled-rejections`\n\nflag (throw, strict, warn, none modes)`process.report.getReport()`\n\non Windows`process.features.typescript`\n\n,`process.features.require_module`\n\n,`process.features.openssl_is_boringssl`\n\n`process.versions.llhttp`\n\n** node:child_process**:\n\n`execArgv`\n\noption in`child_process.fork()`\n\n- Race condition fixes for multiple sockets\n- Empty IPC message handling\n- Inherited stdin returns null instead of process.stdin\n`spawnSync`\n\nRangeError fix- stdin, stdout, stderr, stdio properties now enumerable\n`execFile`\n\nstdout/stderr fixes- stdio streams fix for quick destruction\n\n** node:timers**:\n\n- Unref'd\n`setImmediate`\n\nno longer keeps event loop alive - Edge cases for millisecond values fixed\n- Stringified timer IDs support in\n`clearTimeout`\n\n`clearImmediate`\n\nno longer clears timeouts and intervals- AbortController support in\n`timers/promises`\n\n- 98.4% of Node's timers test suite passes\n\n** node:dgram**:\n\n`reuseAddr`\n\nand`reusePort`\n\noptions fixes`addMembership()`\n\nand`dropMembership()`\n\nwork without interface address\n\n** node:util**:\n\n`parseArgs()`\n\nallowNegative option and default to`process.argv`\n\n`util.promisify`\n\npreserves function name and emits warnings`Buffer.prototype.inspect()`\n\nimprovements\n\n** node:tls**:\n\n`tls.getCACertificates()`\n\nreturns bundled CA certificates- Full certificate bundle support from\n`NODE_EXTRA_CA_CERTS`\n\n`translatePeerCertificate`\n\nfunction- ERR_TLS_INVALID_PROTOCOL_VERSION and ERR_TLS_PROTOCOL_VERSION_CONFLICT errors\n- TLSSocket allowHalfOpen behavior fix\n- Windows TTY raw mode VT control sequences\n\n** node:worker_threads**:\n\n- Worker emits Error objects instead of stringified messages\n`Worker.getHeapSnapshot()`\n\nfor heap tracking- MessagePort communication after transfer fixes\n\n** node:readline/promises**:\n\n`readline.createInterface()`\n\nimplements`[Symbol.dispose]`\n\n- Error handling promise rejection fixes\n\n** node:stream**:\n\n`[Symbol.asyncIterator]`\n\nfor`process.stdout`\n\nand`process.stderr`\n\n** node:perf_hooks**:\n\n`monitorEventLoopDelay()`\n\ncreates IntervalHistogram`createHistogram()`\n\nfor statistical distributions\n\n** node:dns**:\n\n`dns.resolve`\n\ncallback fix (removed extra hostname argument)`dns.promises.resolve`\n\nreturns array of strings for A/AAAA records\n\n** node:os**:\n\n`os.networkInterfaces()`\n\ncorrectly returns scopeid for IPv6\n\n** node:cluster**:\n\n- IPC race condition fixes\n\n** node:module**:\n\n`module.children`\n\narray tracking`require.resolve`\n\npaths option`require.extensions`\n\nsupport`module._compile`\n\ncorrectly assigned`--preserve-symlinks`\n\nflag and NODE_PRESERVE_SYMLINKS=1`node:module.SourceMap`\n\nclass and`findSourceMap()`\n\nfunction\n\n** node:zlib**:\n\n- Zstandard (zstd) compression/decompression with sync, async, and streaming APIs\n\n** node:ws**:\n\n- WebSocket upgrade abort/fail TypeError fixes\n\n**Low-level APIs**:\n\n- HTTPParser binding via\n`process.binding('http_parser')`\n\nusing llhttp - libuv functions:\n`uv_mutex_*`\n\n,`uv_hrtime`\n\n,`uv_once`\n\n- v8 C++ API:\n`v8::Array::New`\n\n,`v8::Object::Get/Set`\n\n,`v8::Value::StrictEquals`\n\n**N-API improvements**:\n\n`napi_async_work`\n\ncreation and cancellation improvements`napi_cancel_async_work`\n\nsupport after queueing- Correct ArrayBuffer and TypedArray handling in\n`napi_is_buffer()`\n\nand`napi_is_typedarray()`\n\n`process.exit()`\n\nnotification in Workers`napi_create_buffer`\n\n~30% faster, uses uninitialized memory`napi_create_buffer_from_arraybuffer`\n\nshares memory instead of cloning- Assertion failure fixes with node-sqlite3 and lmdb\n- IPC error handling improvements\n- 98%+ of Node.js N-API tests now pass\n\n**DOMException**:\n\n- name and cause properties through options object\n\n[Developer experience](#developer-experience)\n\nBun 1.3 includes several improvements to make daily development easier and more productive.\n\n[Better TypeScript defaults](#better-typescript-defaults)\n\nBun's default TypeScript configuration now uses `\"module\": \"Preserve\"`\n\ninstead of `\"module\": \"ESNext\"`\n\n. This preserves the exact module syntax you write rather than transforming it, which true to Bun's design as a runtime that natively supports ES modules.\n\n```\n{\n  \"compilerOptions\": {\n    \"module\": \"Preserve\"\n  }\n}\n```\n\n[Console depth control](#console-depth-control)\n\nControl how deeply `console.log()`\n\ninspects objects with the `--console-depth`\n\nflag or `bunfig.toml`\n\nconfig.\n\n```\nbun --console-depth=5 ./app.ts\n[console]\ndepth = 5\n```\n\n[Smarter TypeScript types](#smarter-typescript-types)\n\n`@types/bun`\n\nnow auto-detects whether to use Node.js or DOM types based on your project. This prevents type conflicts when using browser APIs or Node.js APIs. Note that enabling TypeScript's DOM types alongside Bun will always prefer DOM types, which makes usage of some Bun-specific APIs show errors (for example, Bun's `WebSocket`\n\nclass supports extra options not in the DOM spec).\n\nWe now run [an integration test](https://github.com/oven-sh/bun/tree/6e3359dd16aced2f6fca2a8e2de71f09e0bcb3cb/test/integration/bun-types) on every commit of Bun, to detect regressions and conflicts in Bun's type definitions.\n\n`BUN_OPTIONS`\n\n`BUN_OPTIONS`\n\nSet default CLI arguments with the `BUN_OPTIONS`\n\nenvironment variable.\n\n```\nexport BUN_OPTIONS=\"--watch --hot\"\nbun run ./app.ts\n# Equivalent to: bun --watch --hot run ./app.ts\n```\n\n[Custom User-Agent](#custom-user-agent)\n\nSet a custom User-Agent for `fetch()`\n\nrequests with the `--user-agent`\n\nflag.\n\n```\nbun --user-agent=\"MyApp/1.0\" ./app.ts\n```\n\n[Preload Scripts and SQL Optimization](#preload-scripts-and-sql-optimization)\n\n** BUN_INSPECT_PRELOAD environment variable.** An alternative to the\n\n`--preload`\n\nflag for specifying files to load before running your script:\n\n```\nexport BUN_INSPECT_PRELOAD=\"./setup.ts\"\nbun run ./app.ts\n# Equivalent to: bun --preload ./setup.ts run ./app.ts\n```\n\n** --sql-preconnect flag.** Establish a PostgreSQL connection at startup using\n\n`DATABASE_URL`\n\nto reduce first-query latency:\n\n```\nexport DATABASE_URL=\"postgres://localhost/mydb\"\nbun --sql-preconnect ./app.ts\n```\n\nThe connection is established immediately when Bun starts, so your first database query doesn't need to wait for connection handshake and authentication.\n\n[Standalone Executable Control](#standalone-executable-control)\n\n** BUN_BE_BUN environment variable.** When running a single-file executable created with\n\n`bun build --compile`\n\n, set this variable to run the Bun binary itself instead of the embedded entry point:\n\n```\n# Build an executable\nbun build --compile ./app.ts --outfile myapp\n# Run the embedded app (default)\n./myapp\n# Run Bun itself, ignoring the embedded app\nBUN_BE_BUN=1 ./myapp --version\n1.3.0\n```\n\nThis is useful for debugging compiled executables or accessing Bun's built-in commands.\n\n[Run binaries from packages with different names](#run-binaries-from-packages-with-different-names)\n\nYou can now use the `--package`\n\n(or `-p`\n\n) flag with `bunx`\n\nto run a binary from a package where the binary's name differs from the package's name. This is useful for packages that ship multiple binaries or for scoped packages. This brings `bunx`\n\n's functionality in line with `npx`\n\nand `yarn dlx`\n\n.\n\n```\n# Run the 'eslint' binary from the '@typescript-eslint/parser' package\nbunx --package=@typescript-eslint/parser eslint ./src\n# Run a specific version\nbunx --package=typescript@5.0.0 tsc --version\n```\n\nIf you have feedback, `bun feedback`\n\nsends feedback directly to the Bun team. This opens a form to report bugs, request features, or share suggestions.\n\n[Utilities](#utilities)\n\nBun 1.3 ships utility functions for common tasks.\n\n`Bun.stripANSI()`\n\n`Bun.stripANSI()`\n\n`Bun.stripANSI()`\n\nis a 6-57x faster drop-in replacement for the `strip-ansi`\n\nnpm package. Remove ANSI escape codes from strings with SIMD-accelerated performance.\n\n`Bun.stripANSI()`\n\nalso includes numerous improvements to escape sequence parsing, correctly handling cases known to fail in `strip-ansi`\n\n, like [XTerm-style OSC sequences](https://github.com/chalk/strip-ansi/issues/43).\n\nTo get started, just replace `import { stripANSI } from \"strip-ansi\"`\n\nwith `import { stripANSI } from \"bun\"`\n\n.\n\n``` js\nimport { stripANSI } from \"bun\";\n\nconst colored = \"\\\\x1b[31mRed text\\\\x1b[0m\";\nconst plain = stripANSI(colored); // \"Red text\"\n```\n\n`Bun.hash.rapidhash`\n\n`Bun.hash.rapidhash`\n\nUse the Rapidhash algorithm for fast non-cryptographic hashing.\n\n``` js\nimport { hash } from \"bun\";\n\nconst hashValue = hash.rapidhash(\"hello\");\n// => 9166712279701818032n\n```\n\n`postMessage`\n\ngets up to 500x faster\n\n`postMessage`\n\ngets up to 500x faster is the most common way to send data between multiple worker threads in JavaScript. In Bun 1.3, we’re making\n\n`postMessage`\n\n`postMessage`\n\nsignificantly faster:**Strings**: 500x faster** Simple objects**: 240x faster\n\nThis improves performance for worker communication and deep object cloning.\n\nBy avoiding serialization for strings we know are safe to share across threads, it's **up to 500x faster** and uses **~22x less peak memory** in [ this benchmark](https://github.com/oven-sh/bun/blob/b1417f494d389f4c75c21cfc6303d2a7a08a66d1/bench/postMessage/postMessage-string.mjs).\n\nString Size | Bun 1.2.21 | Bun 1.2.20 | Node 24.6.0 |\n|---|---|---|---|\n| 11 chars | 543 ns | 598 ns | 806 ns |\n| 14 KB | 460 ns | 1,350 ns | 1,220 ns |\n| 3 MB | 593 ns | 326,290 ns | 242,110 ns |\n\nThe optimization kicks in automatically when you send strings between workers:\n\n``` js\n// Common pattern: sending JSON between workers\nconst response = await fetch(\"https://api.example.com/data\");\nconst json = await response.text();\npostMessage(json); // Now 500x faster for large strings\n```\n\nThis is particularly useful for applications that pass large JSON payloads between workers, like API servers, data processing pipelines, and real-time applications.\n\n[Processes & Shell](#processes-shell)\n\nBun 1.3 improves process spawning and shell scripting.\n\n[Timeout option](#timeout-option)\n\nKill spawned processes after a timeout with the `timeout`\n\noption.\n\n``` js\nimport { spawn } from \"bun\";\n\nconst proc = spawn({\n  cmd: [\"sleep\", \"10\"],\n  timeout: 1000, // 1 second\n});\n\nawait proc.exited; // Killed after 1 second\n```\n\n[Limit process output with ](#limit-process-output-with-maxbuffer)`maxBuffer`\n\n`maxBuffer`\n\nThe `maxBuffer`\n\noption in `Bun.spawn`\n\n, `spawnSync`\n\n, and `node:child_process`\n\nmethods automatically kills the spawned process if its output exceeds the specified byte limit. This prevents runaway processes from consuming excessive memory:\n\n``` js\nimport { spawn } from \"bun\";\n\nconst proc = spawn({\n  cmd: [\"yes\"],\n  maxBuffer: 1024 * 1024, // 1 MB limit\n  stdout: \"pipe\",\n});\n\nawait proc.exited; // Killed after 1 MB of output\n```\n\nThis is particularly useful when running untrusted commands or processing user input where output size is unpredictable.\n\n[Enhanced Socket Information](#enhanced-socket-information)\n\n`Bun.connect()`\n\nsockets now expose additional network information through new properties:\n\n``` js\nimport { connect } from \"bun\";\n\nconst socket = await connect({\n  hostname: \"example.com\",\n  port: 80,\n});\n\nconsole.log({\n  localAddress: socket.localAddress, // Local IP address\n  localPort: socket.localPort, // Local port number\n  localFamily: socket.localFamily, // 'IPv4' or 'IPv6'\n  remoteAddress: socket.remoteAddress, // Remote IP address (previously available)\n  remotePort: socket.remotePort, // Remote port number\n  remoteFamily: socket.remoteFamily, // 'IPv4' or 'IPv6'\n});\n```\n\nThese properties provide complete visibility into both ends of a socket connection, useful for debugging, logging, and network diagnostics.\n\nPipe streams to spawned processes with ReadableStream `stdin`\n\n``` js\nimport { spawn } from \"bun\";\n\nconst response = await fetch(\"https://example.com/data.json\");\n\nconst proc = spawn({\n  cmd: [\"jq\", \".\"],\n  stdin: response.body,\n});\n```\n\n[Other process improvements](#other-process-improvements)\n\n: Pass runtime arguments to forked processes`execArgv`\n\nin`child_process.fork()`\n\n: Control event loop references`process.ref()`\n\n/`process.unref()`\n\n**Bun Shell reliability improvements**: More robust shell implementation\n\n[Performance improvements](#performance-improvements)\n\nBun 1.3 includes performance improvements across the runtime.\n\n**Idle CPU usage reduced**: Fixed GC over-scheduling; Bun.serve timer only active during in-flight requests** JavaScript memory down 10-30%**: Better GC timer scheduling (Next.js -28%, Elysia -11%): I/O threadpool optimization`Bun.build`\n\n60% faster on macOS**Express 9% faster, Fastify 5.4% faster**:`node:http`\n\nimprovements: Rewritten using setTimeout implementation`AbortSignal.timeout`\n\n40x faster: Optimized for common headers`Headers.get()`\n\n2x faster: Optimized for common headers`Headers.has()`\n\n2x faster: Optimized for common headers`Headers.delete()`\n\n2x faster: Memory usage optimization`setTimeout`\n\n/`setImmediate`\n\n8-15% less memory**Startup 1ms faster, 3MB less memory**: Low-level Zig optimizations** SIMD multiline comments**: Faster parsing of large comments** Inline sourcemap ~40% faster**: SIMD lexing`bun install`\n\n2.5x faster for node-gyp packages: Buffered summary output`bun install`\n\n~20ms faster in large monorepos: Fixed bug that re-evaluated workspace packages multiple times`bun install`\n\nfaster in workspaces: Significant performance improvements on Windows`bun install --linker=isolated`\n\n: Only fetches package manifests, not tarballs`bun install --lockfile-only`\n\nmuch faster**Faster WebAssembly**: IPInt (in-place interpreter) reduces startup time and memory usage: setImmediate performance fix`next build`\n\n10% faster on macOS: Uses uninitialized memory for large allocations, matching Node.js behavior`napi_create_buffer`\n\n~30% faster**NAPI: node-sdl 100x faster**: Fixed napi_create_double encoding** Faster sliced string handling in N-API**: No longer clones strings when encoding allows it** Highway SIMD library**: Runtime-selected optimal SIMD implementations narrow the performance gap between baseline and non-baseline builds** Faster number handling**: Uses tagged 32-bit integers for whole numbers returned from APIs like`fs.statSync()`\n\n,`performance.now()`\n\n, reducing memory overhead and improving performance`fs.stat`\n\nuses less memory and is faster**Improved String GC Reporting Accuracy**: Fixed reference counting for correct memory usage reporting** Reduced memory usage in**: Optimized Dirent class implementation with withFileTypes option`fs.readdir`\n\n: Lower memory usage when reading large amounts of data or long-running streams`Bun.file().stream()`\n\nreduced memory usage**Bun.SQL memory leak fixed**: Improved memory usage for many/large queries: Native C++ implementation`Array.prototype.includes`\n\n1.2x to 2.8x faster: With untyped elements in Int32 arrays`Array.prototype.includes`\n\n~4.7x faster: With untyped elements in Int32 arrays`Array.prototype.indexOf`\n\n~5.2x faster: C++ implementation instead of JavaScript`Number.isFinite()`\n\n~1.6x faster: JIT compilation`Number.isSafeInteger`\n\n~16% faster**Polymorphic array access optimizations**: Calling same function on Float32Array, Float64Array, Array gets faster** Improved NaN handling**: Lower globalThis.isNaN to Number.isNaN when input is double** Improved NaN constant folding**: JavaScriptCore upgrade** Optimized convertUInt32ToDouble and convertUInt32ToFloat**: For ARM64 and x64 architectures: Improved server-side hot reload performance`server.reload()`\n\n30% faster**TextDecoder initialization 30% faster**: Caches 34 HTTP methods as common strings`request.method`\n\ngetter micro-optimized**Numeric hot loops optimization**: WebKit update with loop unrolling** Reduced memory usage for child process IPC**: When repeatedly spawning processes** Embedded native addons cleanup**: Delete temporary files immediately after loading in`bun build --compile`\n\n**Zero-copy JSON stringifier**: Eliminates memory allocation/copying for large JSON strings** String concatenation optimizations**: Patterns like`str += str`\n\ngenerate more efficient JIT code: When string and index are constants`String.prototype.charCodeAt()`\n\nand`charAt()`\n\nfolded at JIT compile-time: More efficient algorithms for arrays with holes`Array.prototype.toReversed()`\n\noptimized**Reduced memory usage for large fetch() and S3 uploads**: Proper backpressure handling prevents unbounded buffering** WebKit updates**: Optimized MarkedBlock::sweep with BitSet for better GC performance** WebKit updates**: JIT Worklist load balancing and concurrent CodeBlockHash computation** WebKit updates**: String concatenation like`str += \"abc\" + \"deg\" + var`\n\noptimized to`str += \"abcdeg\" + var`\n\n**WebKit updates**: Delayed CachedCall initialization and improved`new Function`\n\nperformance with sliced strings**Optimized internal WaitGroup synchronization**: Replaced mutex locks with atomic operations for high concurrent tasks** Threadpool memory management**: Releases memory more aggressively after 10 seconds of inactivity\n\n[Bug Fixes](#bug-fixes)\n\nBun 1.3 includes hundreds of bug fixes. Here are the highlights:\n\n**Package manager:**\n\n- bun.lock now formats with proper newlines and spacing\n- bun pm pack now correctly includes files starting with \"./\" from package.json\n- Fixed bun.lock parsing with workspace overrides when package names differ\n- Fixed assertion failure from invalid Semver versions with extra wildcards during package installation\n- Fixed bun install --frozen-lockfile bug when using overrides (now sorts overrides consistently and includes unused overrides in lockfile)\n- Fixed bun pack directory-specific pattern exclusion (exclusion patterns now work for nested files, not just top level)\n- Fixed global package postinstall scripts not running even when explicitly opted in via trustedDependencies\n- Fixed bun --install=force <script.ts> not respecting the --install=force flag\n- Fixed cache invalidation issue with \"browser\" field in package.json being ignored after server import\n- bun install no longer crashes when printing HTTP errors\n- Fixed crash with very long package names in package.json parsing\n- Fixed HTTPS client proxy reliability issue causing hangs when installing dependencies (impacted Codex)\n- Fixed potential infinite loop when installing packages in projects with very large number of dependencies\n- Fixed error handling for private git dependencies in bun install\n- Fixed dependency resolution priority to devDependencies > optionalDependencies > dependencies > peerDependencies for consistency with other package managers\n- Fixed bun install bug when passing multiple packages via CLI with certain dependency types\n- Fixed bun install lifecycle script failures when directory deleted during install\n- Fixed bun shell $-prefixed variables in package.json scripts\n- Fixed crash during bun install permissions errors in non-interactive environments\n- Fixed bun install assertion failure with malformed/oversized integrity hash in bun.lockb\n- Fixed assertion failure parsing package.json with top-level catalog configurations\n- Fixed non-deterministic module resolution for packages with both CJS and ESM\n- Fixed panic installing global package with --trust if dependencies already trusted\n- Fixed crash during bun install with malformed patch file\n- bun install integer overflow parsing package versions fixed (affected @google/gemini-cli@nightly, @scratch/paper)\n- bun install ETXTBUSY error when linking package binaries fixed\n- Fixed catalog dependencies not handled correctly in bun update\n- Fixed bun init listing CLAUDE.md twice in summary\n\n**Runtime:**\n\n- Fixed bytesWritten calculation in node:net when handling buffered string writes\n- Fixed process.stdin buffering issue on macOS where input wasn't emitted incrementally\n- Fixed potential exit signal hanging in loops\n- Fixed SharedArrayBuffer crashing on transfer\n- Fixed crash when accessing cookies before proper initialization\n- Fixed \"undefined is not an object\" error when interrupting Next.js dev server with Ctrl+C\n- Fixed Worker events not being emitted in some cases (e.g., \"close\" event)\n- Fixed Worker terminate Promise not resolving in some cases\n- Fixed fs.Dir.close regression\n- Fixed Symbol() and Symbol(\"\") formatting in Bun.inspect to correctly show Symbol()\n- Fixed AbortSignal being garbage collected too early when passed to fetch or Bun.spawn without event listener\n- Buffer.copy(), Buffer.from(), and multiple write/compare/indexOf methods now pass more Node.js tests\n- Fixed automatic flushing of pending filesystem writes before process exit for Bun.file(path).writer()\n- Fixed dynamic imports of \"bun\" package to return proper named exports instead of {default: globalThis.Bun}\n- Fixed createRequire() to work with virtual paths that don't exist on disk (fixes Nuxt in Vite 6)\n- Fixed vite build issue that caused incorrect or interleaved file writes\n- Fixed DuckDB native module crashes from null-returning modules in napi_register_module_v1\n- Fixed os.loadavg() to return accurate system CPU load averages on macOS\n- Fixed S3 multipart upload edge case that could crash the process\n- Fixed Bun.deepEquals() comparison of empty objects with same prototype but different internal types\n- Fixed loader: \"object\" plugin to correctly handle __esModule property\n- Bun.Glob: Fixed bugs with directory matching and ** patterns\n- File writer no longer prematurely closes file descriptors it doesn't own\n- FormData boundary in fetch Content-Type header no longer includes quotes (matches Node.js)\n- React JSX runtime correctly loads react-jsx vs react-jsxdev based on NODE_ENV\n- process.stdin correctly resumes after unref/ref cycles\n- Bun.file().stat() and .delete() now work correctly with non-ASCII paths\n- Fixed hang when calling pause() on process.stdin - paused stdin streams no longer prevent process exit\n- Fixed net.Socket error handlers receiving JSC::Exception objects instead of proper Error instances\n- Fixed process.argv in --print and --eval modes to exclude [eval] argument (now matches Node.js)\n- Fixed glob pattern parsing for nested braces like {a,{d,e}b}/c\n- Fixed Node-API compatibility: each module now gets its own napi_env, preventing conflicts when loading multiple modules\n- Fixed Node-API error handling to return error codes instead of crashing on null pointers\n- Fixed Node-API object properties to have correct flags\n- Fixed Node-API version detection for APIs like finalizers\n- Fixed node:net connect() infinite loop when called with null/undefined arguments\n- Fixed node:net socket.write() argument validation to throw appropriate errors for invalid types\n- Fixed node:net allowHalfOpen to properly close writable side when readable side ends\n- Fixed node:net socket timeout validation for invalid values (negative, Infinity, non-numbers)\n- Fixed node:net server.unref() to persist when called before listen()\n- Fixed node:net server.close() callback handling to properly register as one-time event listener\n- Fixed node:net ipv6Only option to properly disable dual-stack support\n- Fixed console.log() to display String objects as [String: \"value\"] matching Node.js behavior\n- Fixed EventEmitter captureRejections validation for better error messaging\n- Fixed setImmediate performance issue causing unnecessary event loop idling with setInterval timers\n- Fixed Unicode property escapes in RegExp (e.g., \\p{Script=Hangul}) affecting webpack compatibility\n- Fixed WebSocket close() and terminate() error handling when internal instance is unavailable\n- Fixed socket error messages to include syscall, address, and port properties\n- Fixed WebSocket upgrades with Bun.serve() explicit route handlers\n- Fixed ReadableStream error messages for type: \"direct\" to be more descriptive\n- Fixed File() constructor to handle empty body with specified name\n- Fixed memory error in ED25519 crypto key generation from private keys that could cause unpredictable behavior or crashes\n- Fixed UDP socket address not resetting after connection in both Bun.udpSocket and node:dgram module\n- Fixed bun-plugin-svelte not properly handling \"svelte\" export condition for packages like @threlte/core\n- Fixed setTimeout incorrectly emitting TimeoutNaNWarning when delay parameter not specified\n- Fixed trailing slashes in Bun.s3 presign causing incorrect URL generation\n- Fixed global catch-all routes with callback handlers in Bun.serve() not working properly\n- Fixed node: prefix not being maintained in module resolution\n- Fixed module.id for entrypoints not correctly reporting \".\" for entry point module\n- Fixed N-API string conversion edge cases in napi\n*get_value_string*_ and napi*create_string*_ functions - Fixed shell crash when spawning many processes very quickly using Bun's shell API ($)\n- Fixed ReferenceError message format to match Node.js behavior (\"X is not defined\" vs \"Can't find variable: X\")\n- Fixed node:crypto hash names returned in uppercase instead of lowercase in getHashes() and getCiphers()\n- Fixed node:vm options handling where undefined values would throw errors instead of using defaults\n- Improved error messages for unsupported libuv functions in NAPI modules (previously showed cryptic \"missing symbol called\" crashes)\n- Fixed Bun.write() to correctly throw error when called on Blob created from Buffer or TypedArray\n- Fixed Bun.write() to properly handle creating directory trees when writing empty files\n- Fixed Object.assign() to correctly copy properties from StatFs class instances\n- Fixed AbortSignal static methods (timeout, abort, any) to work in environments without DOM\n- Fixed crypto.Hmac regression where options.encoding set to undefined would throw instead of using default 'utf8'\n- Fixed crypto.DiffieHellman issue where verifyError on prototype threw invalid this error\n- Fixed Bun.serve redirects with empty streams not including response body\n- Fixed node:crypto.createCipheriv throwing INVALID_ARG_VALUE with empty options object (now infers authTagLength)\n- Fixed node:net.Server.prototype.address() returning incorrect result when listening on localhost (now properly resolves hostname)\n- Fixed garbage collection edge case in node:fs where input buffers could be collected too early causing crashes\n- Fixed HTML imports with custom loaders - can now use type: \"text\" with HTML files\n- Fixed bytecode compilation with 'bun' module imports - all import styles now work\n- Fixed node:crypto setAAD undefined checks - handles undefined options.encoding and options.plaintextLength\n- Fixed string finalizers in N-API - finalizers no longer execute while other JavaScript code is running\n- Fixed require.extensions index out of bounds crash when assigning and removing multiple custom extension handlers\n- Fixed queueMicrotask error handling to throw ERR_INVALID_ARG_TYPE for invalid arguments\n- Fixed typo in ReadableStream.prototype.tee() (fllags → flags) that could cause incorrect canceled stream state checks\n- Fixed rare crash when importing invalid file URLs\n- Fixed crash in Bun.plugin with recursive plugin calls through proper exception handling\n- Fixed TextDecoder encoding label handling to properly throw errors for invalid labels with null bytes and return normalized encoding names\n- Fixed TextDecoder 'fatal' option to properly coerce values to boolean instead of requiring strict boolean types\n- Fixed worker_threads stability issues (multiple bug fixes)\n- Fixed new TextDecoder(\"utf-8\", undefined) throwing error instead of ignoring undefined argument\n- Fixed BroadcastChannel.prototype.unref() returning undefined instead of the BroadcastChannel instance\n- Fixed ERR_EVENT_RECURSION not being thrown when expected\n- Fixed /* wildcard route having higher precedence than method-specific routes\n- Fixed crash with await in rare cases (JavaScriptCore upgrade)\n- Fixed spec edgecase in eval (JavaScriptCore upgrade)\n- Fixed spec edgecase with bitshifting right on objects implementing toString (JavaScriptCore upgrade)\n- Fixed stability issue with Bun.plugin module resolution that could lead to crashes\n- Fixed BunRequest.clone() not preserving cookies and params\n- Fixed new Bun.CookieMap(object) incorrectly validating input object as HTTP header\n- Fixed net.Socket constructor validation for fd option\n- Fixed missing async in function declarations when top-level await present in circular dependencies\n- Fixed rare crash in Bun.spawn\n- Added missing JavaScript exception checks in native code with automated detection to prevent future regressions\n- Fixed console warning in Bun's runtime error page\n- Fixed crash when calling napi_delete_async_work multiple times on same work handle\n- Fixed crash when exiting Worker inside N-API addon\n- Fixed potential crash in N-API class constructors via Reflect.construct or when subclassed\n- Fixed crash in process.env when invalid environment variables passed at startup\n- Fixed potential invalid UTF-8 output in console.log and other APIs\n- Fixed hypothetical stdout truncation from Bun.spawn on Linux/macOS when child exits before data fully read\n- Fixed crash when writing to already-closed Bun.connect socket\n- Fixed crash when ReadableStream garbage-collected during Worker termination\n- Fixed missing default export in browser polyfills for Node.js addons (crypto, http, https, net, tty, util)\n- Fixed Request constructor to store redirect option, preventing fetch() from incorrectly allowing redirects with redirect: \"manual\"\n- Fixed bug where Content-Type header could be removed after accessing request.body from FormData or certain ReadableStream objects\n- Fixed unref'd setTimeout/setInterval not executing in very tiny applications\n- Fixed WebSocket \"error\" event to include Error object instead of string\n- Fixed Bun.S3 presigned URLs to sort query parameters alphabetically for valid signature generation\n- Fixed fetch() to allow overriding Connection header instead of always setting to keep-alive\n- Fixed Bun.S3 HTTP-only S3_ENDPOINT loading from environment variables\n- Fixed bun shell EPIPE error handling\n- Fixed rare crash in Bun.which()\n- Fixed Bun.inspect to show file size for Response objects with Bun.file\n- Fixed thread-safety issue in zlib module when using Zstandard streams\n- Fixed potential crash in node:crypto X509Certificate with invalid input\n- Fixed crash in bun shell when using pipelines with built-in commands that exit immediately\n- Fixed $.braces() support for Unicode characters and deeply nested expansions\n- Fixed --linker=isolated bug with lifecycle scripts containing non-ASCII characters\n- Fixed .write(), .writer(), .unlink(), .delete() on read-only Blob not throwing error (now throws correctly)\n- Fixed Bun.resolve() and Bun.resolveSync() throwing raw values instead of Error objects\n- Fixed crash in Bun.s3.unlink() when S3 credentials not configured\n- Fixed string coercion of statusText to Response constructor\n- Fixed Response.redirect() not throwing RangeError with invalid status codes\n- Fixed environment variables from .env being truncated if longer than 4096 characters (also prevented crash)\n- Fixed Invalid source map errors incorrectly logged in next dev --turbopack\n- Fixed hypothetical bug where uncaught exception in process.nextTick or microtask not reported\n- Fixed assertion failure reading files with odd number of bytes using utf16le or ucs2 encoding\n- Fixed assertion failure when Worker calls process.exit\n- Fixed bug in Error.prepareStackTrace when called with null, undefined, or non-array second argument\n- Fixed bug where N-API exceptions propagated to JavaScript too quickly causing crashes\n- Fixed structuredClone bugs with non-transferable objects\n- Fixed Bun.hash.xxHash64 to correctly handle BigInt seeds larger than 32-bits\n- Fixed server.stop() bug when called while requests still processing\n- Fixed Bun.serve adding duplicate Date headers\n- Fixed stack traces missing frames after accessing error.stack\n- Fixed Error subclasses showing constructor frame instead of throw location as first frame\n- Fixed ESPIPE error when reading from TTY stream after stdin closes\n- Fixed child_process.spawnSync RangeError with process.stderr/stdout in stdio option\n- Fixed socket.write() throwing exception with Uint8Array\n- Fixed crypto.verify() error when null/undefined algorithm passed for RSA key\n- Fixed N-API napi_strict_equals using Object.is instead of === operator\n- Fixed N-API napi_call_function crash when recv argument is null pointer\n- Fixed napi_create_array_with_length handling of negative/oversized lengths\n- Fixed child_process stdin/stdout/stderr/stdio properties not enumerable\n- Fixed Request body streaming with node-fetch buffering large bodies in memory\n- Fixed Buffer.from(string, 'utf-16le') producing incorrect output in rare cases\n- Fixed N-API assertion failure when napi_reference_unref called during garbage collection\n- Fixed new Buffer.isAscii() using wrong implementation (was using isUtf8)\n- Fixed async_hooks noisy warning when using React/Next.js\n- Fixed crypto.randomInt not calling callback\n- Fixed onResolve and onLoad plugin hooks not running for entrypoint files\n- Fixed runtime plugins onResolve not resolving dynamic import() calls\n- Fixed modules with top-level await missing async keyword\n- Fixed crypto.subtle.importKey exception with RSA private keys with CRT parameters\n- Fixed HTMLRewriter errors not propagating as catchable JavaScript errors\n- Fixed assertion failure with BUN_INSPECT_CONNECT_TO and .env file loading\n- Fixed crash when using Bun.secrets on Linux\n- Fixed fetch() throwing Decompression error: ShortRead with empty gzip/brotli/zstd responses\n- Fixed structuredClone() failing with nested objects/arrays containing Blob/File\n- Fixed structuredClone() not preserving File.name property\n- Fixed error stack traces being truncated\n- Fixed WebSocket not emitting error event before close on handshake failure\n- Fixed bun --watch crash when file is deleted\n- Fixed bun --watch not handling swap file changes\n- Fixed shell crash with environment variable assignments in pipeline\n- Fixed bun patch internal data structure line indexing\n- fetch() now handles multi-frame zstd-compressed responses with Transfer-Encoding: chunked\n- fetch() with AbortSignal now aborts during socket connection (not just after)\n- console.log Error object truncated stack trace fixed\n- Infinite loop logging Error with circular reference fixed (error.stack = error, circular error.cause)\n- Rare crash in Bun.serve during garbage collection fixed\n- Crash when Bun.plugin onResolve returned undefined/null fixed\n- UDP socket crash when process exiting fixed\n- Rare race condition in fetch() with many simultaneous redirects and AbortSignal fixed\n- Bun.serve stability issue with large request bodies fixed\n- BUN_CONFIG_VERBOSE_FETCH=curl now prints request body for application/x-www-form-urlencoded\n- Crash with large number of command-line arguments when accessing process.argv fixed\n- Fixed NODE_NO_WARNINGS environment variable to be respected\n- Fixed shell lexer incorrectly displaying = token as + in error messages\n- Fixed namespace import objects incorrectly inheriting from Object.prototype\n- Fixed bun:ffi new CString() ignoring byteOffset argument when byteLength not provided\n- Fixed crash in bun:ffi with pointers encoded as 32-bit integers\n\n**Bundler/transpiler:**\n\n- Nested objects in macros with numeric property keys now work correctly\n- Crash when macro returned complex/deeply-nested object or array fixed\n- Fixed crash when parsing invalid shell syntax\n- Fixed stack overflow in JavaScript parser with deeply nested expressions (refactored to use less stack space)\n- Fixed build.module() failing to parse TypeScript with loader: 'ts'\n- Fixed banner option with format: \"cjs\" and target: \"bun\" producing syntax error with shebang\n- Bundler syntax error messages improved for invalid escape sequences outside string literals\n`require.main === module`\n\nwith --target=node no longer incorrectly rewritten to`require.main === require.module`\n\n- bun build --compile smarter about default output filenames, avoids attempting to write to directories\n- Fixed bundler identifier collisions with block-scoped variables during minification\n- Fixed inconsistent floating point math results in JavaScript transpiler vs runtime\n- Fixed util.inherits missing in bun build --target=browser\n- Fixed bundler onLoad plugins with loader: \"file\"\n- Fixed sourcemap: true in Bun.build to actually generate sourcemaps (previously only accepted string enum)\n- Fixed bun build generating invalid code for cyclic imports with top-level await\n- Fixed bundler plugins unable to intercept entry points with onResolve\n- bun build hanging with cyclic asynchronous module dependencies fixed\n- Missing async keyword in bundled modules with top-level await in certain edge cases fixed\n- Fixed assertion failure in JavaScript lexer when parsing invalid template string in JSX\n- Fixed dead code elimination for unused pure function calls in comma expressions during minification\n- Fixed parsing JSX namespaced attributes with numeric identifiers\n\n**Test runner:**\n\n- Fixed Jest globals (expect, test, describe) availability in imported test files\n- Fixed VS Code extension test running with special characters in test names\n- Fixed test runner to accept non-string describe labels (numbers, functions, classes)\n- Fixed test timeout behavior with spawnSync - tests now properly timeout and terminate child processes\n- Fixed test.failing with done callbacks - properly handles error passing and throwing\n- Fixed bun:test -t filter to hide skipped and todo tests from output\n- Fixed bun:test memory corruption causing test names to corrupt when beforeEach hook threw error\n- Fixed beforeAll hooks running for describe blocks with no matching tests\n- Fixed expect(() => { throw undefined }).toThrow(ErrorClass)\n- Fixed jest.fn().mockRejectedValue() causing unhandled rejection when never called\n- Fixed bun test not filtering tests correctly when directory name passed as argument\n- Fixed bun test displaying wrong line for test.failing() warnings\n- Fixed toIncludeRepeated checking for at least N occurrences instead of exactly N (now matches Jest)\n- Fixed bun test failing with multiple test files using node:test module\n- Fixed expect(...).toBeCloseTo(...) not counted in total expect calls in bun test\n- Test execution order rewritten for improved reliability and predictability, especially for describe blocks and hooks (beforeAll, afterAll)\n- Uncaught promise rejection in async test no longer causes test runner to hang\n- test() and afterAll() inside another test() callback now throw error instead of being ignored\n- test.only nested inside describe.only now executes only innermost .only tests\n- describe.only now correctly skips beforeAll hooks in non-.only describe blocks\n- Async beforeEach hook failure now prevents corresponding test from running\n- Test hooks (beforeAll, beforeEach) now support timeout option and fail if exceeded\n- afterAll hook now runs even if beforeAll hook fails (aligns with Jest)\n- Error in beforeAll hook from --preload now correctly halts test execution across all files\n- Error in describe block now correctly skips nested describe blocks\n- describe.todo() incorrectly executed when nested inside describe.only() fixed\n- Passing test inside describe.todo() block now handled correctly\n- Error in async beforeEach hook now reported correctly instead of \"unhandled error between tests\"\n- Custom matchers from jest-dom now work (this.utils.RECEIVED_COLOR, this.utils.EXPECTED_COLOR)\n- vi.resetAllMocks, vi.useFakeTimers, vi.useRealTimers now stubbed\n- Clearer error messages for --reporter and --coverage-reporter flags\n- bun test loading files with . in path now works correctly\n- Fixed toMatchInlineSnapshot to properly recognize hard tabs in indentation matching\n- expect().toEqual() now handles error.cause and enumerable properties\n- Fixed expect(...).toHaveBeenCalledWith() now showing colorful diff on failure\n\n**Memory usage:**\n\n- Fixed N-API handle scopes race condition and memory leak in garbage collection\n- Fixed Bun.spawn stdio memory leak when piped stdio was never read\n- Fixed memory leaks in development server by properly deinitializing resources on shutdown\n- Fixed memory leak in Bun.spawn when stdout or stderr set to \"pipe\"\n- Fixed memory leak in Bun.pathToFileURL caused by incorrect reference counting\n- Fixed memory leak in Bun.serve() for requests with certain URLs\n- Fixed memory leak with some strings caused by reference count not being decremented\n- Fixed memory leak with AbortSignal in node:fs operations (fs.promises.writeFile, readFile, etc.)\n- Fixed memory leak in DNS resolution error handling from c-ares (node:dns)\n- Fixed memory leaks in Bun Shell\n- Fixed sourcemap parsing with names field and potential memory leak on parsing failure\n- Fixed memory leak in fs.mkdir and fs.mkdirSync with { recursive: true }\n- Fixed HTMLRewriter crash when element handler throws exception, also fixed CSS selector memory leak\n- Fixed memory leak in Bun.plugin onLoad filters using regex\n\n**SQL:**\n\n- Fixed Bun.SQL reliability issues causing queries to hang or fail when executing many prepared statements simultaneously\n- SQL client must be called as tagged template literal (throws ERR_POSTGRES_NOT_TAGGED_CALL if called as function)\n- SQL numeric values now returned as strings in binary format for safety/consistency with postgres.js\n- SQL idle timeout no longer disconnects during active query processing\n- SQL connection strings now properly handle URL-encoded usernames, passwords, and database names\n- SQL template literal fragments properly handle nesting and parameter concatenation\n- SQL ReadyForQuery state bug fixed (prevented premature disconnection)\n- SQL verify-full and verify-ca SSL modes now correctly handle certificate verification\n- Fixed binary data types and custom type OIDs in PostgreSQL client\n- Fixed Bun.sql PostgreSQL parameter validation and error messaging\n- Fixed PostgreSQL flush() method being undefined\n- Fixed Bun.SQL sql() helper TypeScript types for column name overloads\n- Fixed crash in Bun.SQL when database connection fails\n- Fixed index out of bounds error during large batch inserts in Bun.SQL\n- Fixed Bun.sql client hanging indefinitely during shutdown with pending queries\n- Fixed Bun.SQL Unix domain socket connection failures with PostgreSQL\n- Fixed Bun.SQL WHERE IN clause support for string arrays\n- Fixed DATABASE_URL options precedence in Bun.SQL connection string parsing\n- Bun.sql postgres driver NUMERIC parsing with many digits fixed\n\n**HTTP/TLS:**\n\n- Fixed TLS server identity verification improvements\n- Fixed proper handling of IP range normalization (e.g., \"8.8.8.0/24\")\n- Fixed ERR_SSL_NO_CIPHER_MATCH with unsupported/invalid cipher suites in TLS\n- Fixed Bun.serve() incorrectly rejecting tls array with single configuration object\n- Fixed certificate verification error spelling: UNKKNOW_CERTIFICATE_VERIFICATION_ERROR → UNKNOWN_CERTIFICATE_VERIFICATION_ERROR\n- Fixed HTTP/2 flow control and protocol handling issues\n- Fixed node:http2 sending multiple RST frames when only one should be sent\n- Fixed duplicate Transfer-Encoding header in node:http\n- Fixed Strict-Transport-Security headers to be sent over HTTP (for proxy deployments)\n- Fixed Fastify websockets registration issue in node:http\n- Fixed ERR_HTTP_SOCKET_ASSIGNED in Next.js\n- Fixed rejectNonStandardBodyWrites behavior in node:http module - properly handles undefined and false values\n- Fixed node:http Agent abort handling edge cases\n- Fixed node:http extra arguments handling in http.request URLs\n- Fixed HTTP/1.1 chunked encoding extensions being incorrectly rejected\n- Fixed ERR_STREAM_ALREADY_FINISHED error when cancelling HTTP requests (e.g., page refresh in next dev)\n- Fixed fetch() with large bodies failing with ECONNRESET when using HTTP proxy for HTTPS\n- Fixed fetch() hanging with 101 Switching Protocols response\n\n**CSS parser:**\n\n- Fixed CSS calc() expressions causing stack overflow with nested calculations\n- Fixed radians incorrectly converted to degrees in CSS transform functions\n- Fixed CSS parser bugs (mentioned in description, no specific details in notes)\n- CSS: Fixed light/dark mode handling, color down-leveling, and box-shadow minification\n- CSS: @-webkit-keyframes rule now parsed correctly\n- Added 275+ CSS parser tests and fixed several subtle bugs for improved stability\n- Improved CSS floating point precision by always printing to 6 decimal places for smaller bundle sizes\n- Updated CSS vendor prefixing to latest autoprefixer version\n- Fixed :global() selector in CSS modules not being processed correctly\n- Fixed CSS parser handling of infinity values to render properly in Safari (3.40282e38px vs 1e999px for Tailwind v4 rounded-full)\n- Fixed CSS custom property parser edgecase\n- Fixed code splitting bug where CSS imports in dynamic ES modules pointed to CSS instead of JavaScript\n- Fixed CSS parser bugs with calc() and color-mix() involving hsl()\n- Fixed assertion failure in CSS parser with large floating-point values from TailwindCSS\n- Fixed parsing linear-gradient() with turn angle units\n\n**Windows:**\n\n- Fixed WebKit and libpas dependencies updated for Windows builds\n- bunx no longer throws \"exec\" error on Windows\n- Fixed stat() assertion failure on Windows in node:fs\n- Fixed .npmrc file parsing to handle Byte Order Mark (BOM) conversions, particularly for UTF-16 encoded files on Windows\n- Fixed bun run --filter ignoring NO_COLOR on Windows\n- Fixed fs.accessSync() and fs.existsSync() handling of relative paths with \"../\" segments on Windows\n- Fixed assertion failure on Windows with invalid file paths\n- Windows icon now properly set in executable\n- bunx now works on Windows when installed with npm\n- Fixed bunx yarn failing on Windows due to unnecessary postinstall script\n- Fixed Windows crash with async macros in bundler affecting OpenCode\n- Fixed crash in Windows file watcher when many files change at once (e.g., git branch switch)\n- Fixed integer cast panic when reading large files on Windows\n- Fixed Bun.which on Windows failing to find executables in paths with non-ASCII characters\n- Fixed Windows install.ps1 incorrectly joining PATH with spaces instead of semicolons\n- Fixed bun shell pipelines on Windows\n- Fixed tarball extraction with unusual package names producing invalid temp filename on Windows\n- Windows crash in bun outdated/bun install from race condition fixed\n- Windows assertion failure from incorrect file path fixed\n\n**TypeScript types:**\n\n- Fixed TypeScript type conflicts between Bun, Node.js, and DOM type definitions (Buffer.equals() type errors)\n- Fixed TypeScript declarations so Bun.Env types correctly apply to process.env\n- Fixed generic type parameters for ReadableStream and WritableStream\n- Fixed URLSearchParams type definitions for better @types/node compatibility\n- Fixed TypeScript support for using Bun.$ as a type annotation\n- Fixed spyOn type inference for optional methods (TypeScript types)\n- Fixed CryptoKeyPair global type (TypeScript types)\n- TypeScript legacy decorators now work with computed property names\n- Fixed @types/bun for better TypeScript support (*.svg modules, ShellError types)\n- TypeScript non-null assertions with new operator now work:\n`new obj!.a()`\n\n- Fixed type confusion bug with async generator function as readable stream body\n- Fixed require.main being readonly in TypeScript type definitions\n- Fixed db.transaction() TypeScript types to correctly infer return type and argument types\n\n**Other:**\n\n- Fixed typo in bun upgrade error message (extra closing parenthesis)\n- Fixed terminal syntax highlighter adding extra closing brace } to template literal errors\n- Fixed assertion failure in Bun's logger when processing source locations\n- Sourcemap line numbers off-by-one in Chrome DevTools fixed\n- install.sh now prioritizes ~/.bash_profile over ~/.bashrc for PATH updates\n- npm install bun on Alpine Linux arm64 fixed\n- Stack traces now dim current working directory for better readability\n- Fixed bun run attempting to execute JSON files (e.g., index.json)\n- Fixed TOML parser incorrectly handling table array headers after inline tables\n- Fixed Bun to report ResolveMessage and BuildMessage errors as native errors (allows pnpm to work)\n- Fixed file:// URL encoding issue\n- Fixed bun init -h to show help text\n- Changed SIGPWR signal on Linux for GC thread suspension instead of SIGUSR1 to avoid application conflicts\n- Reliability improvements for filesystem operations - fixed Zig standard library error propagation from system calls\n- CLI help flags now show =<val> to indicate they accept values\n\n[Breaking changes](#breaking-changes)\n\n**Bun.serve() TypeScript types were reworked**:** Defining the WebSocket data in**to using a pattern popularised by XState. See the`Bun.serve()`\n\nhas changed[new docs here](https://bun.sh/docs/api/websockets#contextual-data). This is due to a[limitation in TypeScript](https://github.com/microsoft/TypeScript/issues/26242).`Bun.Server<T>`\n\nis now generic, with the one type parameter representing the WebSocket`.data`\n\ntype (use`undefined`\n\nor`unknown`\n\nif not using WebSockets)`Bun.ServeOptions`\n\nis now deprecated in favor of`Bun.Serve.Options`\n\n**TypeScript default**:`\"module\": \"Preserve\"`\n\n(was auto-detected)**GC signal**: SIGPWR instead of SIGUSR1 on Linux: requiring files with unknown extensions defaults to the JavaScript loader instead of file loader for Node.js compatibility`require('./file.unknown-extension')`\n\n`bun info`\n\naliased to`bun pm view`\n\n: The`Bun.serve()`\n\nroutes`static`\n\noption has been renamed to`routes`\n\n**SQL client**: Now throws error if called as function instead of tagged template literal (use`sql` query``\n\nor`sql.unsafe()`\n\n)**SQL client**:`undefined`\n\nvalues in the object helper (e.g.`sql({ value: undefined })`\n\n) are now filtered out instead of being treated as`NULL`\n\n. If all values are`undefined`\n\n, this throws a`SyntaxError`\n\n: Now throws`Bun.build`\n\nerrors`AggregateError`\n\nby default on build failures (set`{ throw: false }`\n\nto revert)**Minifier**: Removes unused function and class expression names by default (use`--keep-names`\n\nto preserve)- TypeScript types for\n`bun:test`\n\n's expect matchers were made stricter. Some matchers support relaxing the strictness by passing a type parameter. For example`expect(null).toBe<string | null>(\"hello\")`\n\n: Now fails with error when no tests match the`bun test`\n\nfilter`-t <filter>`\n\nregex (previously succeeded silently): Returns`os.networkInterfaces()`\n\n`scopeid`\n\ninstead of`scope_id`\n\nfor IPv6 interfaces (matches Node.js)**Namespace imports**: Objects from`import * as ns`\n\nno longer inherit from`Object.prototype`\n\n:`bun test`\n\nnesting`test()`\n\nand`afterAll()`\n\ninside another`test()`\n\ncallback now throw error instead of being silently ignored**Node.js version**: Bun now reports as Node.js v24.3.0 instead of v22.6.0 (affects`process.version`\n\n,`process.versions.node`\n\n, and N-API version)\n\nBun 1.3 is the biggest release yet. Try it today:\n\n```\nbun upgrade\n```\n\nOr install Bun for the first time:\n\n```\ncurl -fsSL https://bun.sh/install | bash\n```\n\nWe're excited to see what you build with Bun 1.3. Join us on [Discord](https://bun.sh/discord) and share your projects!", "url": "https://wpnews.pro/news/bun-1-3", "canonical_source": "https://bun.com/blog/bun-v1.3", "published_at": "2025-10-10 20:00:00+00:00", "updated_at": "2026-05-22 20:44:26.647275+00:00", "lang": "en", "topics": ["developer-tools", "open-source", "products", "enterprise-software", "data"], "entities": ["Bun", "MySQL", "Postgres", "SQLite", "Redis", "React", "Vite", "JavaScript"], "alternates": {"html": "https://wpnews.pro/news/bun-1-3", "markdown": "https://wpnews.pro/news/bun-1-3.md", "text": "https://wpnews.pro/news/bun-1-3.txt", "jsonld": "https://wpnews.pro/news/bun-1-3.jsonld"}}