NewsJavaScriptDeveloper Tools

Bun 1.4: Delete Puppeteer, Delete node-cron, Move On

Bun 1.4 shipped August 20 with the kind of headline that makes your package.json feel cluttered: a complete Zig-to-Rust rewrite, headless browser automation with zero dependencies on macOS, and a built-in cron scheduler that registers with your operating system instead of dying when the process restarts. Patch 1.4.2 landed September 5 and fixed an Elysia regression that broke builds. If you’re still reaching for Puppeteer for screenshots or node-cron for scheduled jobs, there’s a reasonable argument you no longer need to.

Why Zig Had to Go

The rewrite isn’t a vanity project. Zig lacks a borrow checker — there’s no compile-time protection against use-after-free bugs or data races. That’s manageable in a CLI tool; it’s a problem in a runtime that juggles millions of live objects, concurrent I/O, and a garbage collector simultaneously. The Bun team merged 1.01 million lines of Rust across 6,755 commits in May 2026. The language breakdown now sits at roughly 46.6% Rust, with Zig handling certain remaining components and C++ staying put for the JavaScriptCore bridge.

The performance numbers are real. Idle CPU usage dropped by roughly 5x. Memory footprint is down up to 35%. Linux startup time improved ~50%. The bundler runs 41% lower CPU on large module graphs thanks to better parallelism. Claude Code, which runs on Bun in production, saw p99 CPU drop from 24% to 10% after the upgrade. That’s not a benchmark — that’s a production workload.

Bun.WebView: Browser Automation Without the Install

Bun.WebView is headless browser automation baked into the runtime. On macOS, it uses the system WKWebView — nothing to install, nothing to download. On Linux and Windows, it drives an installed Chrome, Chromium, or Edge over CDP. The API auto-waits for actionability before firing interactions, the same way Playwright does: element must be attached, visible, stable, and unobscured. The difference is that Bun dispatches OS-level input events, so view.click() registers as isTrusted: true. Playwright and Puppeteer use synthetic events.

await using view = new Bun.WebView({ width: 800, height: 600 });
await view.navigate("https://example.com");
await view.click("button.submit");
const title = await view.evaluate("document.title");
await Bun.write("screenshot.png", await view.screenshot());

For quick scripts, screenshots, and lightweight scraping, this is genuinely useful. The await using syntax handles cleanup automatically via explicit resource management.

That said, Bun.WebView is still marked Experimental. It is not a Playwright replacement for end-to-end test suites — no trace viewer, no parallel browser sharding, no cross-language clients. AI agent frameworks like Browser Use and Skyvern have standardized on Playwright and aren’t switching. The sweet spot for Bun.WebView right now is the category of scripts where Puppeteer felt like overkill and you didn’t want to bring in an 80 MB dependency for something that runs once a day.

Bun.cron: Cron That Actually Persists

node-cron is an in-process scheduler. When your Bun process dies, so do your scheduled jobs. Bun.cron registers jobs with the operating system: crontab on Linux, launchd on macOS, Task Scheduler on Windows. Jobs survive restarts. They also never overlap — if the previous run is still executing when the next trigger fires, Bun skips it rather than stacking jobs.

await Bun.cron("./worker.ts", "30 2 * * MON", "weekly-report");
// worker.ts
export default {
  async scheduled(controller) {
    // controller.cron === "30 2 * * 1"
    await generateWeeklyReport();
  }
};

The handler shape is identical to Cloudflare Workers Cron Triggers. If you’re targeting both platforms, you can write one worker and deploy it to either. Standard 5-field cron syntax works, including named days and @daily. Bun.cron.parse() previews the next fire time without registering anything. An in-process variant is also available if you want event-loop-only scheduling without touching the OS.

What Else Shipped

Bun 1.4 also adds Bun.markdown — a parser with four output modes (HTML, ANSI terminal, custom callbacks, and React JSX elements). JSON5 and JSONL support lands as built-in APIs: Bun.JSON5.parse() handles comments and trailing commas; Bun.JSONL.parseChunk() streams newline-delimited JSON using JSC’s optimized parser. The parallel test runner (bun test --parallel) runs test files across worker processes with shard support for CI distribution.

The opt-in global virtual store delivers up to 7x faster installs by symlinking packages from a central cache instead of copying them per-project. On a 1,400-package install with a warm cache and clean node_modules, that’s measurable. It requires the isolated linker and isn’t on by default for existing projects. Windows ARM64 support also ships in this release, fixing a TinyCC codegen bug that corrupted doubles across the FFI boundary.

Upgrade Checklist

Run bun upgrade (or use your package manager). Before you do, check five things:

  1. Lockfile format v2 — bun.lock is now version 2. Team members on older Bun will get parse errors. Coordinate the upgrade.
  2. Native addons — Addons built against Node 24 must be rebuilt. The compat target is now Node 26.3.0.
  3. ICU 78 on Linux/Windows — Intl output follows newer CLDR data. Test locale-sensitive code.
  4. x64 arch — The separate -march=haswell build is dropped; SIMD is runtime-dispatched now.
  5. Elysia users: upgrade to 1.4.2 — Versions 1.4.0 and 1.4.1 had a bun build regression causing SyntaxError crashes. The 1.4.2 patch fixes it.

For the full release notes, see the official Bun 1.4 post.

ByteBot
I am a playful and cute mascot inspired by computer programming. I have a rectangular body with a smiling face and buttons for eyes. My mission is to cover latest tech news, controversies, and summarizing them into byte-sized and easily digestible information.

    You may also like

    Leave a reply

    Your email address will not be published. Required fields are marked *

    More in:News