This article is published in English.
Bun 1.4 Built-ins That Can Replace sharp, Puppeteer, node-pty and More
A practical tour of Bun 1.4's built-in image, browser, Markdown, cron, terminal, parallel script and test features, plus how to trial them safely in real projects.
A typical JavaScript project accumulates a dependency for every capability it needs: sharp for images, a Markdown parser, Playwright or Puppeteer for browser automation, a cron library, node-pty for pseudo-terminals, concurrently or npm-run-all for parallel scripts, and a pile of CI configuration to make tests fast. Bun 1.4 takes a different position: many of those jobs can live inside the runtime. This guide walks through the new built-ins with the snippets you need to try each one, and suggests a low-risk way to evaluate them.
According to the release announcement, Bun 1.4 shipped on August 20, 2026, adding more than 1,500 Node.js compatibility tests, fixing over 2,900 issues and cutting idle CPU and memory use. APIs this new can still change, so treat the details below as a snapshot and confirm them against the official Bun 1.4 announcement and current docs. The theme of the release is less about raw speed and more about shrinking the toolchain.
Installing or upgrading
Bun can be installed with a shell script, npm, Homebrew, PowerShell on Windows, or as a Docker image. Each labeled line below is one alternative; pick the one that matches your environment:
--curl
curl -fsSL https://bun.sh/install | bash
--npm
npm install -g bun
--brew
brew install oven-sh/bun/bun
--powershell
powershell -c "irm bun.sh/install.ps1 | iex"
--docker
docker pull oven/bun
If Bun is already on your machine, a single command moves you to the latest release:
bun upgrade
Image processing with Bun.Image
Bun.Image brings decoding, resizing, rotation and encoding of common formats into the runtime, so you no longer need a native image dependency. The chain below reads a JPEG, fits it inside a 1024 by 1024 box while preserving aspect ratio, rotates it, encodes it as WebP at quality 85 and writes the result:
await Bun.file("photo.jpg")
.image()
.resize(1024, 1024, { fit: "inside" })
.rotate(90)
.webp({ quality: 85 })
.write("thumb.webp");
Because every step returns the same builder, a pipeline reads top to bottom like a recipe. Typical uses include upload thumbnails, avatar resizing, JPEG-to-WebP conversion, image APIs, and optimizing assets before they reach storage.
Bun reports that its implementation beats sharp in several of its own benchmarks, including resizing and encoding a 1080p PNG. The more durable benefit is removing a native module that often complicates Docker builds and CI caches. If you depend on advanced sharp features, check that the operations you use exist before switching.
Headless browser automation with Bun.WebView
Bun.WebView is a built-in headless browser API that can navigate, click, scroll, evaluate JavaScript and capture screenshots. Note the await using declaration: it ties the view's lifetime to the enclosing scope so the browser is released automatically when the block exits, even on errors.
await using view = new Bun.WebView({
width: 800,
height: 600,
});
await view.navigate("https://bun.sh");
await view.click("a[href='/docs']");
const title = await view.evaluate("document.title");
await Bun.write(
"page.png",
await view.screenshot()
);
The script opens a page, follows a link, reads the document title and saves a screenshot. That covers many small jobs without adding a full automation framework: screenshot services, smoke tests, scraping helpers, uptime checks, link checkers and simple QA flows. When you need lower-level control, Bun.WebView offers an escape hatch to the Chrome DevTools Protocol. For large end-to-end suites with cross-browser needs, a dedicated tool is still likely the better fit.
Rendering Markdown with Bun.markdown
Bun.markdown converts Markdown to several targets. The simplest returns an HTML string:
const html = Bun.markdown.html(
"# Hello **world**"
);
It can also produce React elements directly, which is handy when a component renders a README or docs page:
export default function Page() {
return Bun.markdown.react(readme);
}
Rendering can be customized further, for example to format output for a terminal. GitHub-Flavored Markdown extensions such as tables, task lists, strikethrough and autolinks are supported. This suits documentation sites, developer portals, blogs, README viewers, CLI help, knowledge bases and interfaces that display model-generated Markdown.
One caveat matters more than the rest: the HTML output is not sanitized. Any Markdown from users, third parties or an LLM must pass through a sanitizer before it reaches a browser, or you are exposed to script injection.
Scheduled jobs with Bun.cron
Bun.cron() works in two modes. In the first, it registers a job with the operating system's scheduler: crontab on Linux, launchd on macOS and Task Scheduler on Windows. The call takes a script path, a cron expression and a job name; this one runs a worker every Monday at 02:30:
await Bun.cron(
"./worker.ts",
"30 2 * * MON",
"weekly-report"
);
Because the OS owns the schedule, the job runs even when no Bun process is alive. In the second mode, the schedule lives inside the running process, here firing every five minutes. The using declaration stops the job when its scope ends:
using job = Bun.cron(
"*/5 * * * *",
async () => {
await cleanupTempFiles();
}
);
Runs never overlap, and explicit time zones are supported. Good candidates are cleanup workers, reports, database maintenance, data sync, email batches and periodic polling. Keep in mind that in-process jobs vanish when the process restarts, and if you run several replicas, each will fire unless you add coordination.
Running scripts in parallel
bun run --parallel replaces concurrently and npm-run-all. Pass several script names to run them at once:
bun run --parallel build test
Glob patterns select a family of scripts:
bun run --parallel "build:*"
Combined with --filter, the same flag runs a script across every workspace:
bun run --parallel --filter '*' build
Normally one failure stops everything; --no-exit-on-error lets the remaining tasks finish, which is useful for collecting all test failures at once:
bun run --parallel --no-exit-on-error --filter '*' test
Each output line is prefixed with the script that produced it, so interleaved logs stay readable. In a monorepo this replaces a sequential chain like the following with work spread across your CPU cores:
package A → build
package B → build
package C → build
Parallel runs do not understand dependencies between packages, so if one package must build before another, you still need ordering or a task runner that models the graph.
Faster test runs
bun test gains a --parallel flag:
bun test --parallel
You can set the number of worker processes explicitly:
bun test --parallel=4
Files are handed to workers dynamically rather than split into fixed batches up front, so one slow file does not leave other workers idle. Three related flags target CI. Sharding splits the suite across machines, here taking the first of three slices:
bun test --shard=1/3
Running only the tests affected by your changes shortens local feedback loops:
bun test --changed
Recording durations lets later runs balance work using real timing data:
bun test --timings=timings.json
Parallel execution exposes tests that share state, such as a common database, fixed ports or temp files. Expect to fix some isolation issues the first time you enable it.
Fixing vulnerable dependencies
Security upkeep gets a built-in command:
bun audit fix
It upgrades vulnerable packages to patched versions and installs them. When a fix requires a major version bump, Bun reports it instead of applying it; add --latest to opt in. Review those major upgrades like any breaking change. In CI this folds dependency security into the normal install step.
Removing duplicate dependencies
Large projects often carry several near-identical versions of one package:
esbuild@0.15.10
esbuild@0.15.11
When a single version satisfies every requirement, this command collapses the duplicates:
bun dedupe
The check variant fails with an error when duplicates remain, which makes it a natural CI gate:
bun dedupe --check
Fewer duplicates mean smaller dependency trees, faster installs, less disk use, simpler maintenance and potentially smaller deployments.
Driving interactive programs with Bun.Terminal
Bun.Terminal is a built-in pseudo-terminal, which lets JavaScript control interactive programs such as these without node-pty:
bash
vim
htop
A pseudo-terminal matters because such programs behave differently when they detect a real terminal: they draw full-screen interfaces, use colors and expect keystrokes. That makes Bun.Terminal relevant for developer tools, CLIs, terminal dashboards, remote development tools, interactive automation and AI coding agents, which increasingly work directly in a shell.
Node.js compatibility and Next.js
The change with the widest impact may be compatibility rather than any new API. The release adds 1,517 Node.js tests and reports improvements in modules including http, fs, stream, cluster, timers, zlib and vm. It also calls out better support across several categories: frameworks (Next.js 16, Nuxt, Fastify), testing tools (Vitest, Playwright, Testcontainers), observability (OpenTelemetry and Datadog's dd-trace) and data or infrastructure clients (TypeORM, RabbitMQ and AWS S3).
The --bun flag forces a tool's CLI to run under Bun instead of the Node.js binary named in its shebang. According to the release, this works with Next.js 16.3, Turbopack and the React Compiler:
bun --bun next build
Adoption ultimately depends on whether your existing application survives the switch, so a successful build of your own project is worth more than any published benchmark.
Performance claims in context
Bun's benchmarks for 1.4 show up to five times lower idle CPU, meaningfully lower memory in HTTP workloads and faster startup on Linux and Windows. These are vendor-run numbers, so read them as directional. Lower CPU, memory and startup time can translate into cheaper, more responsive services, but only your own workloads can confirm it. For a broader view of the runtime trade-offs, see our comparison of Node.js, Deno and Bun.
A low-risk way to evaluate Bun 1.4
Moving a production system wholesale is rarely wise. Small, reversible experiments work better.
Start a new API
Scaffold a project and build a small service with Bun.serve:
bun init
Replace one image workflow
Port a single sharp pipeline to Bun.Image and compare output quality and timing.
Move one scheduled task
Pick a simple cron job and reimplement it with Bun.cron().
Parallelize your tests
Run the existing suite in parallel and note which tests break because of shared state:
bun test --parallel
Clean up dependencies
Try the security and deduplication commands on a branch and review the diff:
bun audit fix
bun dedupe
Build your Next.js app under Bun
Run the production build with the Bun runtime and compare it against your current pipeline:
bun --bun next build
In every case, measure the results rather than relying on published benchmarks.
The consolidation trend
Bun 1.4 is less about a list of new APIs than about one runtime absorbing work that used to belong to separate packages. The rough shape is a runtime layer with Node.js APIs, a tooling layer covering tests, scripts, security, CI and terminals, and a library layer for images, Markdown, browsers and cron:
Bun 1.4
│
┌─────────┼──────────┐
│ │ │
Runtime Tooling Libraries
│ │ │
Node.js Testing Image
APIs Scripts Markdown
Security Browser
CI Cron
Terminal
The npm ecosystem gained its power from composing thousands of small packages, but that power has a cost in dependencies, configuration, compatibility work, security updates and fragmented tooling. Bun bets on the opposite: ship useful primitives inside the runtime.
Key takeaways
- The question worth asking has shifted from "is Bun faster than Node.js?" to "which parts of my stack could Bun replace?"
- Built-ins reduce native dependencies, but check feature parity before replacing mature libraries such as
sharpor Playwright. - Sanitize
Bun.markdownHTML output whenever the input is untrusted. - Parallel scripts and tests are quick wins, but they surface hidden ordering and shared-state problems.
- Treat vendor benchmarks as a hypothesis and validate each feature against your own workloads before committing.