Developer Tools

Bun 1.4 Absorbed Your Dependencies. Read the Stability Labels

Bun 1.4 ships image processing, a headless browser and a Markdown parser in the runtime. The stability labels decide which ones you can rely on.

TechLogHub Editorial
September 25, 2026
6 min read
0 views

Share Article

Three Bun 1.4 APIs stacked by documentation stability label: Bun.Image solid, Bun.WebView and Bun.markdown dashed.

Bun 1.4 Absorbed Your Dependencies. Read the Stability Labels

Quick answer: Bun 1.4 (20 August 2026) ships image processing, a headless browser, a Markdown parser, a cron scheduler and a pseudo-terminal inside the runtime. Deleting sharp and Playwright from your package.json is premature: Bun.WebView is marked experimental and needs an installed Chrome on Linux and Windows, and Bun.markdown is marked unstable. Bun.Image carries no such warning and is the one worth adopting now.

The interesting thing about Bun 1.4 is not the benchmark numbers, though they are there: 5× lower idle CPU, up to 35% less memory, 50% faster startup on Linux. It is the scope. A JavaScript runtime now ships an image pipeline and a browser.

That is not a Bun-only trend. Node 26 ships node:sqlite; Deno has Deno.cron built in. All three runtimes are pulling the long tail of npm inside the binary. The question worth asking is not whether the feature exists but whether the vendor has committed to it yet — and Bun's own documentation answers that per-API, if you read it.

What landed, and what it displaces

APIReplacesMarked in docs
Bun.Imagesharp, jimpNo warning
Bun.WebViewPuppeteer, PlaywrightExperimental
Bun.markdownmarked, remarkUnstable

Also new: Bun.cron() for scheduled jobs, Bun.Terminal for native pseudo-terminals, bun run --parallel, bun test --parallel, and three dependency commands — bun audit fix, bun dedupe and bun prune.

Bun.Image is the one that is ready

It decodes JPEG, PNG, WebP, HEIC, AVIF, BMP, TIFF and GIF, and encodes JPEG, PNG, WebP, HEIC and AVIF — BMP, TIFF and GIF are decode-only. The chained API reads well:

await Bun.file("photo.jpg")
  .image()
  .resize(400, 400, { fit: "inside" })
  .webp({ quality: 80 })
  .write("thumb.webp");

Resize takes filter, fit ("fill" or "inside") and withoutEnlargement; the constructor takes autoOrient and maxPixels. That maxPixels ceiling matters if you accept user uploads — it is the decompression-bomb guard you would otherwise wire up yourself.

The errors are typed rather than stringly: ERR_IMAGE_FORMAT_UNSUPPORTED, ERR_IMAGE_TOO_MANY_PIXELS, ERR_IMAGE_DECODE_FAILED, so you can branch on error.code instead of matching messages. One platform wrinkle the docs call out directly: TIFF decode rejects with ERR_IMAGE_FORMAT_UNSUPPORTED on Linux. If your dev machine is a Mac and CI is Linux, that is a test that passes locally and fails in the pipeline.

For build-time thumbnail generation this is a straight win: one fewer native dependency, one fewer postinstall, one fewer thing that breaks on architecture changes. For ad-hoc conversion outside a build you do not need a runtime at all — an image format converter in the browser is faster than writing the script.

Bun.WebView has a platform asterisk

The pitch is strong: "a headless browser built into the runtime," usable "without Puppeteer, Playwright, or a separate browser download." Methods are what you would expect — navigate(), evaluate(), screenshot(), click(), type(), press(), scroll(), plus raw cdp() access.

The same page qualifies it two ways. First: "This API is experimental and may change in future releases." Second, and more consequential for CI: only macOS gets the zero-dependency path, via the system WKWebView. On Linux and Windows, Bun drives an installed Chrome, Chromium, Edge, Brave or Playwright's chrome-headless-shell over the Chrome DevTools Protocol. The default backend is "webkit" on macOS and "chrome" everywhere else.

Read that carefully. On a Linux CI runner you still install a browser, and you also swap rendering engines between your laptop and the pipeline. WebKit on macOS, Chromium on CI, for the same screenshot test. That is a worse position than the Playwright setup it replaces, not a better one.

Three further limits are documented: only one navigation may be in flight per view at a time, the Chrome backend is main-thread only and throws if constructed inside a Worker, and WebP screenshots require the Chrome backend. Fine for a scripted scrape or a one-off render; thin for a test suite.

Bun.markdown is fast and explicitly unstable

A Rust parser with GitHub Flavored Markdown extensions — tables, strikethrough and task lists on by default — and three entry points: Bun.markdown.html(), Bun.markdown.render() for custom callbacks, and Bun.markdown.react() for JSX. The docs label it: "This API is under active development and may change in future versions of Bun."

Worth flagging for anyone rendering user-submitted Markdown: there is a tagFilter option implementing the GFM disallowed-HTML-tag filter, but the documentation does not present this as a sanitiser. Treat the output as untrusted HTML and sanitise downstream, exactly as you would with marked. If all you need is a one-off conversion, a Markdown to HTML converter saves the round trip.

The changes that will actually bite you

Set the new APIs aside; 1.4 is a breaking release regardless.

The lockfile moves to version 2. Older Bun versions cannot read it. Upgrade the whole team and every CI image in one go, or someone gets an unreadable lockfile on a branch.

New monorepos default to the isolated linker. Existing lockfiles keep the hoisted layout, so this only hits fresh repos — but a package that quietly relied on hoisting will not resolve. Worth knowing before you scaffold.

Bun.cron interprets schedules in local time, not UTC. Same crontab string, different firing time, no error. If you have jobs already running under an earlier Bun, check them against the container's timezone.

Temporal is on by default (disable with BUN_JSC_useTemporal=0), and the Node compatibility target moves to v26.3.0 with NODE_MODULE_VERSION 147 — recompile native addons. Bun reports adding 1,517 tests from the Node test suite in this release, which is the more meaningful compatibility signal than the version number. If you are tracking Node's own direction, the Node 26 type-stripping changes are the other half of the picture.

How to decide

Use the stability label as the decision rule, not the feature list. An API with no warning is one the vendor will hesitate to break. An API marked experimental is a preview you are welcome to use and will be expected to fix yourself.

Node applies the same logic in the opposite direction: node:sqlite is documented at "Stability: 1.2 — Release candidate" as of Node 26.10, years after it first appeared. Runtimes absorbing dependencies is real and probably good. Runtimes absorbing dependencies at production quality on day one is not what is happening yet.

Practical split: adopt Bun.Image for build-time work now, use Bun.WebView for scripts rather than test suites, keep a real Markdown library wherever the output is user-facing, and re-check all three next quarter. The same evaluation applies to any open-source package you are considering dropping — and to migrations generally, as the Vite 8 changeover showed. If you are still choosing a runtime, the developer tools directory is a better starting point than a benchmark chart.

FAQ

Can Bun 1.4 replace sharp?

For common resize-and-encode work, yes. Bun.Image carries no experimental marking, handles the major formats and exposes typed error codes. Check the Linux TIFF decode limitation if your inputs include TIFF.

Does Bun.WebView remove the need for Playwright in CI?

Not on Linux or Windows. There it drives an installed Chrome, Chromium, Edge, Brave or Playwright's chrome-headless-shell over CDP, so a browser still has to be present. Only macOS uses the system WebKit with no extra install.

Is the Bun 1.4 lockfile backwards compatible?

Partially. Bun 1.4 reads older v0 and v1 lockfiles, but older Bun versions cannot read the new lockfileVersion: 2. Upgrade developer machines and CI images together.

Why did my scheduled job move after upgrading?

Bun.cron now interprets schedules in local time instead of UTC. The expression is unchanged and no error is raised, so the shift is silent. Check the timezone your container actually runs in.

Is Bun.markdown safe for user-generated content?

Treat it like any other Markdown renderer: sanitise the HTML afterwards. It offers a GFM tagFilter option, but the docs do not present the parser as a sanitiser, and the API is marked unstable.

Do I need to recompile native addons for Bun 1.4?

Yes. The Node compatibility target moves to v26.3.0 and NODE_MODULE_VERSION is now 147, so anything built against the previous ABI needs rebuilding.


A feature in the runtime is not the same as a feature you can depend on.

Stay Updated

Get the next deep dive in your inbox

Subscribe for product analysis, engineering explainers, and practical guides published on TechLogHub.

See what launched this week

One email a week: new and trending developer tools, fresh comparisons, and what shipped. Unsubscribe in one click.

Bun 1.4 Built-in APIs: What to Trust | Developer Tools | TechLogHub