Зачем bun переписывают на RUST разбор изнутри

09.07.2026 · 5 мин

Когда у Bun — 22 миллиона загрузок в месяц и среди пользователей Vercel, Railway и DigitalOcean — даже «мелкий» баг перестаёт быть мелким. Список свежих проблем в релизе v1.3.14 выглядит так, будто рантайм не просто спотыкается, а системно ломается на одном и том же классе ошибок.

Проблема, которую нельзя замалчивать

Bun — один из самых амбициозных проектов в экосистеме JavaScript. Внутри него сразу несколько инструментов: транспайлер TypeScript в JavaScript, бандлер, менеджер пакетов, тест-раннер и реализация Node.js API. Всё это должно работать быстро. И оно действительно работает быстро. Но цена скорости оказалась высокой.

В последнем релизе исправляли heap-use-after-free, use-after-free в node: zlib и node: http2, heap out-of-bounds write в UDPSocket, memory leak в crypto.scrypt, double-free в CSS-парсере и race condition в MessageEvent. Это не один случайный сбой, а повторяющийся класс ошибок.

Почему так вышло

Bun написали на Zig. Это язык с низкоуровневым контролем, близкий по философии к C, но без стандартной библиотеки и с упором на простоту. Проблема в том, что Bun одновременно живёт в двух мирах: JavaScript с garbage collection и Zig с ручным управлением памятью.

JavaScriptCore сам управляет памятью для JS-объектов, а Zig требует от разработчика явно решать, кто и когда освобождает данные. Когда эти модели смешиваются, появляется постоянный риск ошибок: кто владеет объектом, где его освобождать, что делать при исключении, не указывает ли указатель уже на удалённую память.

ЖИЗНЕННЫЙ ЦИКЛ ПАМЯТИ В BUN
─────────────────────────────────────────────────────────
┌──────────────┐         ┌──────────────────┐
│  JavaScript  │         │      Zig/Rust     │
│  (GC-мир)    │         │  (ручное управление) │
└──────┬───────┘         └────────┬─────────┘
       │                           │
       │   Передача данных         │
       │   между мирами            │
       ▼                           ▼
┌──────────────────────────────────────────────┐
│  Где именно освобождать? Кто владеет?         │
│  Что если выбросили исключение?               │
│  А если фьюзер поменял данные?                 │
└──────────────────────────────────────────────┘
Главная сложность — граница между GC-миром и ручным управлением памятью.

Команда Bun пыталась закрывать проблему разными способами: патчила Zig-компилятор для Address Sanitizer, гоняла тесты через ASAN на каждом коммите, использовала Fuzzilli для фаззинга рантайм-API и писала много интеграционных тестов на утечки памяти. Это серьёзный уровень дисциплины, но даже его оказалось недостаточно.

Почему RUST

Автор статьи не обвиняет Zig: другие проекты на Zig не сталкиваются с таким количеством проблем. Но сценарий Bun редкий — почти никто не проектирует язык специально под смесь GC и ручного управления памятью.

Rust предлагает то, чего в этой ситуации не хватало: систему владения и заимствования, гарантию выполнения cleanup-кода через drop, а также защиту от целого класса ошибок на уровне компилятора. Если память освобождена неправильно, если объект используется после освобождения или если читается неинициализированная память, компилятор это поймает заранее.

Для Bun это означает меньше use-after-free, double-free и утечек, которые раньше приходилось искать вручную.

Что конкретно меняется

Команда использует пререлизный Claude Fable 5 для помощи в переписывании части кода. Это не отменяет инженерную работу, но ускоряет перевод логики на Rust и генерацию эквивалентов.

Переход можно описать как смену парадигмы: от «умные правила, тесты и ASAN» к «ошибки этого класса невозможны по дизайну».

ПУТЬ К СТАБИЛЬНОСТИ BUN
────────────────────────
                        ┌─────────────────────┐
 Zig-подход             │  Умные правила +    │
 ────────────────      │  человеческий       │
                        │  код-ревью          │
                        └──────────┬──────────┘
                                   │
                                   ▼
                        ┌─────────────────────┐
                        │  Много тестов,      │
                        │  ASAN, фаззинг       │
                        └──────────┬──────────┘
                                   │
                                   ▼
                        ┌─────────────────────┐
                        │  Rust: баги этого    │
 Rust-подход            │  класса невозможны   │
 ────────────────      │  по дизайну          │
                        └─────────────────────┘
Rust переносит часть гарантий из тестов и ревью в сам язык.

Какие компромиссы

Переезд на Rust не бесплатный. Rust сложнее Zig, компиляция может стать дольше, а команде нужно будет привыкнуть к новой модели разработки. Кроме того, Bun всё равно взаимодействует с JavaScript GC, так что граница между Rust и JavaScriptCore останется зоной повышенного внимания.

Это большой рефакторинг, но команда идёт на него осознанно. И при этом признаёт, что без Zig Bun вообще не появился бы в текущем виде.

Выводы

Переход Bun на Rust — это попытка убрать целый класс ошибок, а не просто переписать код ради моды. Для пользователей это означает меньше крашей в production, более предсказуемую работу и большую уверенность в долгосрочной поддержке.

Если эксперимент удастся, он может задать новый стандарт для Node.js-совместимых рантаймов. Bun уже быстрый; после перехода на Rust он может стать ещё и заметно надёжнее.

Ссылки

Дмитрий Полухин — продуктовый дизайнер. Пишу про разработку, AI и дизайн интерфейсов. Обо мне, контакты и профили.