Bun — инструментарий для сборки и тестирования full-stack приложений на JavaScript и TypeScript. Bun 1.4 добавляет 1517 тестов из набора тестов Node.js — самый большой скачок совместимости с Node.js со времён версии 1.0. Также релиз закрывает более 2900 issue, снижает холостое потребление CPU в 5 раз, снижает потребление памяти до 35% и ускоряет запуск на Linux на 50%. В версию вошли Bun.Image, Bun.WebView, Bun.markdown, Bun.cron(), Bun.Terminal, bun run --parallel, bun test --parallel, bun audit fix, bun dedupe и bun prune. Кроме того, рантайм переписан с Zig на Rust.

Материал охватывает все изменения, вышедшие с версии Bun 1.3.0.

Для обновления:

bun upgrade

Совместимость с Node.js

Bun создаётся как drop-in замена для Node.js. В набор тестов, запускаемых на каждом коммите Bun, добавлено 1517 тестов из тестового набора самого Node.js.

График прохождения тестового набора Node.js в Bun: с 1450 в версии 1.2.0 до 3743 в версии 1.4.0

Модули node:http, node:fs, node:cluster, node:timers, node:zlib, node:vm и node:stream проходят 97% собственных тестов Node; node:quic — 99%; node:events, node:trace_events и node:sqlite — 100%.

Bun пока не совместим с Node.js на 100%, но на практике значительная часть существующей JavaScript-экосистемы работает без изменений. Прогресс совместимости с тестовым набором Node.js можно отслеживать на отдельной странице проекта.

Playwright

Playwright теперь работает на Bun: можно управлять браузером через connectOverCDP(), запускать набор тестов командой playwright test с конфигом playwright.config.ts, открывать --ui и запускать Chromium на Windows.

Next.js 16

bun --bun next build работает с Next.js 16.3, Turbopack и React Compiler.

vitest

vitest запускается под Bun, включая --coverage, с пулами threads и forks.

OpenTelemetry

Инструментация http и fs из OpenTelemetry экспортирует spans, а пакеты shimmer и require-in-the-middle патчат забандленный код.

dd-trace

dd-trace трейсит запросы, а @datadog/pprof непрерывно профилирует; C++ API V8, на которые они опираются, реализованы.

Дополнительные улучшения совместимости с Node.js

С каждым релизом Bun приближается к полной совместимости с Node.js. Без изменений теперь работают:

  • Nuxt: nuxt dev подключает HMR и Nuxt DevTools.
  • testcontainers и dockerode: работает container.exec().
  • https-proxy-agent и socks-proxy-agent: http.request() туннелирует через них.
  • crawlee: обходит через proxy-chain.
  • @grpc/grpc-js и ConnectRPC: работают серверы за Envoy и клиенты за AWS ALB.
  • amqplib: подключается к RabbitMQ.
  • @aws-sdk/client-s3: работает потоковая загрузка.
  • TypeORM: запускается с настройками декораторов из tsconfig.json.
  • nock: перехватывает запросы http и https.
  • Fastify inject() и light-my-request: работают.
  • happy-dom: больше не ломает console.log.
  • piscina: работает.

Новые API Node.js в Bun:

  • worker_threads: опции resourceLimits, stdout, stderr и eval.
  • ws: события 'upgrade' и 'unexpected-response'.
  • socket.upgradeTLS({ isServer: true }): серверный STARTTLS.
  • node:cluster: разделяет слушающие сокеты между воркерами.
  • node:repl, node:trace_events, node:domain: реализованы.

Production

Bun 1.4 использует меньше памяти, меньше CPU и запускается быстрее.

До версии 1.4 Bun использовал два аллокатора памяти — libpas от JavaScriptCore и mimalloc. Теперь JavaScriptCore в Bun использует mimalloc (что улучшает возврат памяти системе), а сам mimalloc расширен возможностями частичной очистки страниц, отдельным потоком-сборщиком, освобождающим память во время простоя JavaScript, и улучшенным ленивым обнулением.

Потребление CPU

Для Claude Code — крупного долгоживущего приложения на Bun — потребление CPU в production снизилось вдвое: p99 упал с 24% до 10%, p50 — с 5,8% до 2,5%.

Потребление CPU Claude Code в production до и после Bun 1.4: p99 с 24% до 10%, p50 с 5,8% до 2,5%

Для небольшого приложения «hello world» холостое потребление CPU снижается в 5 раз.

Холостое потребление CPU hello-world сервера, Bun 1.3 против Bun 1.4: снижение в 5 раз

Этого удалось достичь за счёт оптимизации моментов, когда таймеры сборщика мусора запрашивают GC, перехода JavaScriptCore с обхода Strong-корней в виде связного списка на связный список сегментированных массивов, а также сокращения числа вызовов futex — вместе с упомянутыми изменениями в mimalloc.

Потребление памяти

Приложения с HTTP-серверами на Bun должны увидеть снижение потребления памяти на 13-48%.

Пиковая память под нагрузкой (1 000 000 запросов при 64 соединениях; 100 000 для Next.js и Vite):

СерверBun 1.4Bun 1.3Node.js 26Δ к Bun 1.3
fastify120 MB233 MB156 MB−48%
Express92 MB169 MB145 MB−46%
node:http81 MB135 MB107 MB−40%
Elysia55 MB91 MBn/a−40%
Next.js285 MB397 MB342 MB−28%
Bun.serve36 MB45 MBn/a−20%
Vite dev server233 MB268 MB214 MB−13%

Ещё большее снижение показывает серверный рендеринг с Next.js. На типовом паттерне App Router, который в версии 1.3 неограниченно рос (React.cache + no-store fetch в динамическом роуте), Bun 1.4 стабилизируется на 238 МБ после 4000 страниц — против 410 МБ у Node.

Память на 4000 страницах Next.js App Router SSR: Bun 1.4 стабилизируется на 238 МБ, Node на 410 МБ, Bun 1.3 растёт неограниченно

Запуск

На Windows Bun запускается в 2,5 раза быстрее.

hello.js на WindowsBun 1.4Bun 1.3.14Node.js 26
Время запуска15,5 мс39,0 мс40,1 мс
Пиковая память16,8 MB46,5 MB32,5 MB

На Linux Bun запускается в 2 раза быстрее и использует меньше половины памяти.

hello.js на LinuxBun 1.4Bun 1.3Node.js 26
Время запуска5,1 мс10,9 мс27,2 мс
Пиковая память14,6 MB33,0 MB44,5 MB

Размер бинарника

На Linux и Windows бинарник Bun стал меньше до 17%.

Bun 1.4Bun 1.3.14
Linux x6477,0 MB88,5 MB
Linux arm6476,8 MB87,6 MB
Windows x6484,8 MB93,9 MB
Windows arm6475,1 MB90,2 MB
macOS arm6461,2 MB60,2 MB
macOS x6466,6 MB66,0 MB

Бинарники для macOS стали примерно на 1 МБ больше.

Observability

Привычные инструменты работают с Bun 1.4.

  • bun --cpu-prof записывает .cpuprofile. Открывается в Chrome DevTools или VS Code.
  • bun --heap-prof записывает совместимый с V8 .heapsnapshot. Открывается в Chrome DevTools.
  • node:inspector: Session может запускать и останавливать CPU-профиль во время работы приложения через Profiler.start и Profiler.stop.
  • Datadog: dd-trace трейсит запросы, а @datadog/pprof непрерывно профилирует CPU.
  • OpenTelemetry: пакеты @opentelemetry/instrumentation-http и @opentelemetry/instrumentation-fs из npm работают с node:http и node:fs в Bun. Пакеты shimmer и require-in-the-middle, от которых они зависят, могут патчить забандленный код.
  • Асинхронные стектрейсы: ошибка из fs.promises, fetch(), S3, DNS или crypto указывает на await в коде приложения, а не на нативные фреймы.

Часть возможностей появилась впервые.

--cpu-prof-md

--cpu-prof-md записывает CPU-профиль в формате Markdown, что позволяет находить горячую функцию прямо из терминала: топ функций по self time, дерево вызовов и кто кого вызывает. Файл можно прочитать по SSH, прогнать через grep, вставить в баг-репорт или передать LLM.

bun --cpu-prof-md ./app.ts

--heap-prof-md

--heap-prof-md записывает heap-профиль в формате Markdown, что позволяет из терминала понять, что удерживает память: общий размер, типы, удерживающие больше всего, самые крупные объекты и цепочки, которые не дают им освободиться.

bun --heap-prof-md ./app.ts

bun build --metafile-md

bun build --metafile-md записывает анализ бандла в формате Markdown, показывая, почему бандл получился большим: самые крупные модули, что грузит каждая точка входа, и цепочку импортов, которая затянула каждый файл.

bun build ./src/index.ts --outdir ./dist --metafile-md=./dist/meta.md

process.on("memoryPressure")

Когда операционная система сообщает о нехватке памяти, Bun получает уведомление и эмитит событие "memoryPressure" на process. Это можно использовать, чтобы освободить память до того, как ОС убьёт процесс: очистить кэш, закрыть простаивающие соединения, остановить неактивные воркеры. Работает на macOS, Linux и Windows.

process.on("memoryPressure", (level) => {
  cache.clear();
  pool.drainIdle();
});
  • macOS: kqueue с EVFILT_MEMORYSTATUS — то же событие, которое libdispatch использует для DISPATCH_SOURCE_TYPE_MEMORYPRESSURE. level принимает значение "warning" или "critical".
  • Linux: триггер PSI, записываемый в /proc/pressure/memory (или memory.pressure cgroup), отслеживается через epoll по событию EPOLLPRI. level"critical".
  • Windows: CreateMemoryResourceNotification(LowMemoryResourceNotification), ожидание через RegisterWaitForSingleObject. level"critical".

Потоки (Streams) и тела запросов

ReadableStream, WritableStream и TransformStream теперь реализованы нативно. Они используют меньше памяти, работают быстрее и проходят 100% Web Platform Tests.

Четыре конвейера, каждый перемещает 64 МБ данными по 4 КБ чанками:

  • Скачивание: fetch()DecompressionStream("gzip")TextDecoderStreamfor await
  • Загрузка: fs.createReadStream()CompressionStream("gzip") → тело POST-запроса через fetch()
  • Транскодирование: fs.createReadStream()TextDecoderStreamTextEncoderStreamfs.createWriteStream()
  • Подпроцесс: тело fetch() → stdin процесса cat, затем stdout catfor await

Пропускная способность:

КонвейерBun 1.4Bun 1.3Node.js 26Deno 2.9
Скачивание1519 MB/sn/a204 MB/s530 MB/s
Загрузка179 MB/sn/a78 MB/s137 MB/s
Транскодирование132 MB/s116 MB/s52 MB/s91 MB/s
Подпроцесс751 MB/s505 MB/s256 MB/s170 MB/s

Пиковая память:

КонвейерBun 1.4Bun 1.3Node.js 26.7Deno 2.9
Скачивание57 MBn/a86 MB64 MB
Загрузка60 MBn/a84 MB61 MB
Транскодирование62 MB92 MB72 MB57 MB
Подпроцесс65 MB207 MB106 MB114 MB

Все четыре рантайма запускают один и тот же скрипт. Файловые потоки используют Readable.toWeb() и Writable.toWeb() из node:stream. В Bun 1.3 отсутствуют CompressionStream и DecompressionStream, поэтому для него в этих строках стоит n/a.

Response.clone() и Request.clone() больше не копируют каждый чанк во вторую ветку — клон теперь разделяет чанки тела с оригиналом.

Потоковое тело в 64 МБ, вызов res.clone(), затем чтение обоих тел:

РантаймПиковая памятьВремя
Bun 1.4220 MB96 мс
Bun 1.3311 MB129 мс
Node.js 26382 MB230 мс
Deno 2.9297 MB134 мс

Чтение только клона, без чтения оригинала:

РантаймПиковая памятьВремя
Bun 1.4155 MB63 мс
Bun 1.3243 MB98 мс
Node.js 26318 MB162 мс
Deno 2.9233 MB104 мс

Два вызова arrayBuffer() дают 128 МБ пиковой памяти в первой таблице. В обоих случаях Bun 1.4 экономит одну полную копию тела.