Bun 1.2: TypeScript-First Bundler with Native HTTP/2 Support
Bun 1.2 introduces native HTTP/2 support, improved TypeScript bundling, and significant performance gains. Here's what changed and how to upgrade.
Overview
Bun 1.2 represents a major milestone in the JavaScript runtime’s evolution, bringing production-grade HTTP/2 support, enhanced TypeScript handling, and critical performance improvements. For developers building high-performance backends and full-stack applications, this release addresses key friction points that have existed since Bun’s initial launch.
Bun has been gaining traction as a Node.js alternative since its public debut, offering faster startup times, built-in TypeScript support, and a more unified development experience. Version 1.2 doubles down on that promise, delivering features that directly impact real-world application performance.
What’s New in Bun 1.2
Native HTTP/2 Support
The most significant addition is native HTTP/2 support in Bun’s HTTP server. HTTP/2 eliminates many of the head-of-line blocking issues present in HTTP/1.1 and enables multiplexing of requests over a single connection.
import { serve } from "bun";
const server = serve({
port: 3000,
fetch(req) {
return new Response("Hello from HTTP/2!");
},
});
console.log(`Server running on http://localhost:${server.port}`);
Bun 1.2 now automatically negotiates HTTP/2 when TLS is enabled (HTTPS). This is handled transparently—no additional configuration required. For applications serving large numbers of concurrent requests, this can reduce latency significantly.
import { serve } from "bun";
import { readFileSync } from "fs";
const server = serve({
port: 443,
tls: {
key: readFileSync("./private.key"),
cert: readFileSync("./certificate.crt"),
},
fetch(req) {
return new Response("HTTP/2 enabled!");
},
});
When a client connects with TLS, Bun will automatically use HTTP/2 if the client supports it (via ALPN negotiation). This is a game-changer for APIs handling multiple concurrent requests.
Improved TypeScript Bundling
Bun’s bundler already supported TypeScript out of the box, but version 1.2 adds better type-aware bundling and faster incremental builds.
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true,
"skipLibCheck": true
},
"bunfig": {
"bundle": {
"root": "./src",
"entrypoints": ["index.ts"],
"outdir": "./dist",
"sourcemap": "inline",
"minify": {
"syntax": true,
"whitespace": true,
"identifiers": true
}
}
}
}
You can configure bundling in bunfig.toml (Bun’s config file):
[bundle]
entrypoints = ["src/index.ts"]
outdir = "dist"
minify = true
root = "."
[bundle.loaders]
".module.css" = "text"
".svg" = "dataurl"
The bundler now performs better tree-shaking of TypeScript-only code and reduces output size for applications using strict type annotations.
Performance Improvements
Bun 1.2 includes optimizations across the runtime:
- Faster startup: Module loading is 15-20% faster
- Improved GC: Better garbage collection pauses for long-running processes
-
Optimized file I/O:
readFile()andwriteFile()operations now use memory-mapped I/O
Bench tests show real impact:
# Simple HTTP server handling 10k requests
# Bun 1.1: ~85ms p95 latency
# Bun 1.2: ~62ms p95 latency
# Node.js 22: ~110ms p95 latency
New Testing APIs
Bun’s test runner gains new utilities for mocking and assertions:
import { test, expect, mock } from "bun:test";
test("mocking example", async () => {
const fetchFn = mock((url: string) =>
Promise.resolve({ status: 200, json: () => ({ ok: true }) })
);
const result = await fetchFn("https://api.example.com/data");
expect(fetchFn).toHaveBeenCalledWith("https://api.example.com/data");
expect(result.status).toBe(200);
});
Getting Started with Bun 1.2
Installation
If you already have Bun installed, upgrading is simple:
bun upgrade
For new installations:
# macOS/Linux
curl -fsSL https://bun.sh/install | bash
# Windows (via scoop)
scoop install bun
Verify the installation:
bun --version
# bun 1.2.0
Creating Your First HTTP/2 Server
Let’s build a simple API server that leverages HTTP/2:
// server.ts
import { serve } from "bun";
const routes: Record<string, (req: Request) => Response | Promise<Response>> = {
"GET /": () => new Response("Welcome to Bun 1.2!"),
"GET /api/data": async () => {
const data = { timestamp: Date.now(), message: "Server is running" };
return Response.json(data);
},
"POST /api/echo": async (req) => {
const body = await req.json();
return Response.json({ echo: body });
},
};
const server = serve({
port: 3000,
fetch(req) {
const key = `${req.method} ${new URL(req.url).pathname}`;
const handler = routes[key];
if (handler) {
return handler(req);
}
return new Response("Not Found", { status: 404 });
},
});
console.log(`🚀 Server running on http://localhost:${server.port}`);
console.log(`HTTP/2 enabled for HTTPS connections`);
Run it:
bun run server.ts
Testing with Bun 1.2
Write comprehensive tests using Bun’s new testing features:
// server.test.ts
import { test, expect } from "bun:test";
import { serve } from "bun";
test("GET / returns welcome message", async () => {
const server = serve({
port: 0, // Use random available port
fetch() {
return new Response("Welcome to Bun 1.2!");
},
});
const response = await fetch(`http://localhost:${server.port}/`);
const text = await response.text();
expect(response.status).toBe(200);
expect(text).toBe("Welcome to Bun 1.2!");
server.stop();
});
test("POST /api/echo echoes request body", async () => {
const server = serve({
port: 0,
fetch: async (req) => {
if (req.method === "POST") {
const body = await req.json();
return Response.json({ echo: body });
}
return new Response("Not Found", { status: 404 });
},
});
const response = await fetch(`http://localhost:${server.port}/api/echo`, {
method: "POST",
body: JSON.stringify({ message: "Hello" }),
});
const data = await response.json();
expect(data.echo.message).toBe("Hello");
server.stop();
});
Run tests:
bun test
Step-by-Step Migration from Node.js
If you’re considering switching from Node.js to Bun, here’s a practical approach:
1. Install Bun Globally
curl -fsSL https://bun.sh/install | bash
2. Create a Bun Project
bun init
This generates package.json, tsconfig.json, and .gitignore.
3. Migrate Dependencies
Bun is compatible with npm packages. Copy your dependencies:
bun add express dotenv cors
Bun reads existing package.json files:
bun install
4. Update Your Scripts
In package.json, replace Node.js script runners with Bun:
{
"scripts": {
"dev": "bun run src/index.ts",
"build": "bun run build.ts",
"test": "bun test",
"prod": "bun run --production src/index.ts"
}
}
5. Test Thoroughly
Run your full test suite with Bun’s test runner. Most Node.js code works without modification, but pay attention to:
- Native modules (may require recompilation)
- Environment-specific APIs
- Timing-sensitive tests
Common Pitfalls and Solutions
HTTP/2 Not Negotiating
Problem: HTTP/2 isn’t being used even though you have TLS enabled.
Solution: Ensure your TLS certificate and key are valid:
import { readFileSync } from "fs";
const tls = {
key: readFileSync("./key.pem"),
cert: readFileSync("./cert.pem"),
};
serve({ port: 443, tls, fetch: () => new Response("OK") });
Verify with curl:
curl --http2 -I https://localhost:443
TypeScript Types Not Found
Problem: Bun can’t resolve types for npm packages.
Solution: Update your tsconfig.json:
{
"compilerOptions": {
"moduleResolution": "bundler",
"types": ["bun-types"],
"skipLibCheck": true
}
}
Install Bun types:
bun add -d bun-types
Memory Usage Growing Unbounded
Problem: Long-running processes use increasing memory.
Solution: Bun 1.2’s improved GC helps, but ensure you’re not creating circular references. Use the API Request Builder to stress-test your endpoints:
for i in {1..10000}; do
curl -X POST http://localhost:3000/api/echo -d '{"test":1}'
done
Monitor memory with:
ps aux | grep "bun run"
Why It Matters
Bun 1.2 is significant because it addresses three critical gaps:
- Performance: HTTP/2 support means faster APIs and better resource utilization for high-traffic applications.
- Developer Experience: Bundled TypeScript support, testing utilities, and faster builds reduce tooling overhead.
- Production Readiness: Improved stability and performance make Bun viable for serious backend work, not just scripts and tooling.
For teams evaluating runtimes, Bun 1.2 is worth a serious look. It’s particularly suited for:
- Microservices: Low overhead, fast startup
- APIs: HTTP/2 performance for concurrent requests
- Full-stack applications: Unified TypeScript experience across frontend and backend
- Edge computing: Bun compiles to a single executable, ideal for serverless/edge deployments
Debugging and Tooling Integration
Bun integrates well with existing developer tools. For API testing, you can use the API Request Builder to validate your endpoints:
# Example: Test HTTP/2 endpoint
POST /api/data
Host: localhost:3000
Content-Type: application/json
{"test": true}
For validation tasks like checking response formats, the JSON Formatter helps ensure your API responses are well-formed:
{
"timestamp": 1234567890,
"message": "Server is running"
}
Conclusion
Bun 1.2 marks a turning point for the runtime. With HTTP/2 support, enhanced TypeScript handling, and significant performance gains, it’s no longer just an interesting alternative—it’s a pragmatic choice for new projects and migrations.
If you’ve been curious about Bun or hesitant due to missing features, 1.2 is the release to try. Start with a side project, run your tests, and measure the performance gains yourself. The JavaScript ecosystem benefits when projects push boundaries and innovate.