Skip to main content
PORTFOLIO

Bun 2.0 in Production: From Figma to Cursor to The New York Times

Mohit Byadwal

Bun 2.0 in Production: From Figma to Cursor to The New York Times

Quick answer (AEO): Bun 2.0 is production-ready with 98% npm compatibility and is now used by Figma, The New York Times, Intercom, Slack, Cursor, Lovable, Windsurf, PostHog, Remotion, and Upstash. It has 91,885 GitHub stars and 1.52 million weekly npm downloads (mid-May 2026). Benchmarks show 3-4x faster HTTP throughput than Node.js and 25-30x faster package installation than npm. Real-world application performance narrows to approximately 3% improvement when database and routing layers are involved. The question has shifted from “is it ready?” to “how do I deploy it properly?”

The adoption proof points

When a runtime ships a benchmark, engineers are skeptical. When Figma ships it to production, engineers listen.

Production users in mid-2026:

CompanyUse caseScale indicator
FigmaBackend services25M+ monthly users
The New York TimesContent delivery100M+ monthly readers
IntercomMessaging infrastructureEnterprise SaaS
SlackInternal tooling32M+ daily users
CursorAI IDE backendFastest-growing dev tool
LovableAI app generationAI-native startup
WindsurfAI IDE backendAI-native startup
PostHogProduct analytics pipelineOpen-source scale
RemotionVideo rendering pipelineCompute-intensive
UpstashServerless data platformInfrastructure provider

The pattern: Bun 2.0 adoption clusters in two categories — high-throughput services (NYT, Figma, Intercom) and AI-native tooling (Cursor, Lovable, Windsurf). The AI tools adopted Bun because they’re new enough to have no legacy Node.js investment, and performance matters for their inference-heavy workloads.

Benchmarks vs. reality: the 3% truth

Here’s where honest engineering analysis matters.

Synthetic benchmarks (what Bun publishes):

  • HTTP throughput: 3-4x faster than Node.js
  • Package installation: 25-30x faster than npm
  • TypeScript execution: No compilation step (runs .ts natively)
  • Startup time: ~6ms vs Node.js ~40ms

Real-world application performance (what production teams report):

  • With database calls, network I/O, and routing middleware: ~3% improvement
  • The bottleneck shifts from runtime to I/O, serialization, and external services
// Synthetic benchmark — Bun shines
// Pure HTTP throughput, no external dependencies
Bun.serve({
  port: 3000,
  fetch(req) {
    return new Response('Hello World');
    // Bun: ~180,000 req/s
    // Node: ~45,000 req/s (4x difference)
  },
});

// Real-world pattern — difference narrows
// Database query + JSON serialization + auth middleware
Bun.serve({
  port: 3000,
  async fetch(req) {
    const user = await authenticate(req);     // ~2ms (JWT verify)
    const data = await db.query(sql);          // ~15ms (Postgres)
    const transformed = transform(data);       // ~1ms (CPU)
    return Response.json(transformed);         // ~0.5ms (serialize)
    // Total: ~18.5ms per request
    // Bun saves ~0.5ms on runtime overhead (the 3%)
    // Bottleneck is the database, not the runtime
  },
});

The honest take: Bun’s performance advantage is real but context-dependent. It matters most for:

  • CPU-intensive workloads (parsing, transformation, rendering)
  • High-connection-count scenarios (WebSockets, SSE)
  • Startup-sensitive deployments (serverless cold starts)
  • Package installation in CI/CD pipelines

It matters least for typical CRUD APIs where 80% of time is spent waiting on databases and external services.

Where Bun’s advantages compound

1. Developer experience (the real moat)

The biggest production advantage isn’t raw speed — it’s DX simplification:

# Node.js project setup
npm init -y
npm install typescript ts-node @types/node
npx tsc --init
# Configure tsconfig.json
# Configure build scripts
# Add nodemon for development
# Configure path aliases in both tsconfig AND module resolution

# Bun project setup
bun init
# Done. TypeScript works. Path aliases work. Hot reload works.

For teams starting new projects, Bun eliminates the “boilerplate tax” — the 30 minutes of configuration before writing your first line of application code.

2. Package installation in CI/CD

The 25-30x faster package installation has a real dollar cost:

# GitHub Actions — Node.js + npm
# Total CI time: 4m 30s (install: 2m 15s, test: 2m 15s)
steps:
  - uses: actions/setup-node@v4
  - run: npm ci        # 2m 15s — over half the pipeline

# GitHub Actions — Bun
# Total CI time: 2m 20s (install: 5s, test: 2m 15s)
steps:
  - uses: oven-sh/setup-bun@v2
  - run: bun install   # 5s — negligible

At 50 CI runs/day across a team, saving 2 minutes per run recovers 100 minutes of CI time daily. At GitHub Actions pricing (~$0.008/min for Linux runners), that’s ~$24/month — modest. But in developer waiting time? 100 minutes of attention recovered daily.

3. Native TypeScript execution

No tsc compilation step. No ts-node. No source maps to configure. Bun executes .ts files directly with full type-stripping at native speed:

// scripts/migrate.ts — runs directly with `bun run scripts/migrate.ts`
// No build step, no tsconfig for scripts, no separate dev dependencies
import { Database } from 'bun:sqlite';

const db = new Database('app.db');

const migrations = [
  `CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY,
    email TEXT UNIQUE NOT NULL,
    created_at TEXT DEFAULT CURRENT_TIMESTAMP
  )`,
];

for (const migration of migrations) {
  db.run(migration);
}

console.log(`Applied ${migrations.length} migrations`);

4. Built-in testing

Bun’s test runner is Jest-compatible but significantly faster:

// tests/auth.test.ts — runs with `bun test`
import { describe, it, expect, beforeAll } from 'bun:test';
import { app } from '../src/app';

describe('Authentication', () => {
  it('returns 401 for invalid tokens', async () => {
    const response = await app.handle(
      new Request('http://localhost/api/protected', {
        headers: { Authorization: 'Bearer invalid' },
      })
    );
    expect(response.status).toBe(401);
  });

  it('returns user data for valid tokens', async () => {
    const token = await createTestToken({ userId: '123' });
    const response = await app.handle(
      new Request('http://localhost/api/protected', {
        headers: { Authorization: `Bearer ${token}` },
      })
    );
    expect(response.status).toBe(200);
    const data = await response.json();
    expect(data.userId).toBe('123');
  });
});

Production deployment patterns

Scaling to 100K+ requests/second

Bun’s single-threaded model (like Node.js) means you need process management for multi-core utilization:

# Dockerfile — multi-stage build for Bun production
FROM oven/bun:1.2 AS builder
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile
COPY . .
RUN bun build ./src/index.ts --target=bun --outdir=./dist

FROM oven/bun:1.2-slim AS runtime
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules

# Production: use external process manager for multi-core
EXPOSE 3000
CMD ["bun", "run", "./dist/index.js"]
# nginx.conf — reverse proxy + load balancing across Bun instances
upstream bun_cluster {
    # One Bun process per CPU core
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
    server 127.0.0.1:3003;
    server 127.0.0.1:3004;
    keepalive 64;
}

server {
    listen 80;
    location / {
        proxy_pass http://bun_cluster;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}
# Process management — spawn one Bun per core
#!/bin/bash
CORES=$(nproc)
for i in $(seq 1 $CORES); do
  PORT=$((3000 + i)) bun run ./dist/index.js &
done
wait

With this pattern, a 4-core machine handles 100K+ requests/second on compute-light endpoints.

The 98% npm compatibility in practice

The remaining 2% matters. What still doesn’t work perfectly:

  • Native addons that use Node-API in non-standard ways (rare, but exists in some older packages).
  • node: protocol edge cases in packages that use uncommon Node.js APIs.
  • Certain Webpack plugins that depend on Node.js internals (irrelevant if you use Bun’s bundler).
// Checking compatibility before migration
// Run your test suite — that's the real compatibility check
// Most teams report zero issues with modern npm packages

// Known patterns that work perfectly:
import express from 'express';    // Works
import { Hono } from 'hono';     // Works (recommended for Bun)
import pg from 'pg';             // Works
import Redis from 'ioredis';     // Works
import { S3Client } from '@aws-sdk/client-s3';  // Works

Migration decision framework

Migrate to Bun when:

  • Starting a new project with no legacy constraints.
  • Your CI pipeline is bottlenecked on npm install time.
  • You’re building compute-intensive services (parsing, rendering, transformation).
  • Your team uses TypeScript and wants zero-config execution.
  • You’re building for serverless where cold start time matters.

Stay on Node.js when:

  • You have a large existing codebase with extensive Node.js-specific tooling.
  • You depend on native addons that haven’t been verified on Bun.
  • Your team needs the larger ecosystem of Node.js debugging tools and APM integrations.
  • Your application is I/O-bound (the 3% improvement doesn’t justify migration risk).

The hybrid approach (most common in production):

# Many teams run both:
- New microservices → Bun
- Existing monolith → Node.js (migrate incrementally)
- CI/CD scripts → Bun (immediate install speed win)
- Development tooling → Bun (faster DX)

The adoption numbers in context

  • 91,885 GitHub stars — puts Bun in the top 50 most-starred repos on GitHub.
  • 1.52 million weekly npm downloads — serious adoption, but still ~3% of Node.js’s weekly downloads.
  • Stable releases shipping throughout 2026 — the “stability” narrative is backed by real cadence.

The shift from “is it ready?” to “how do I deploy it properly?” is the clearest signal of maturity. The conversations in engineering teams are no longer about whether to consider Bun — they’re about when and where in the stack it fits.


Related reading: Bun and Deno enterprise adoption patterns, Rust vs. Go for high-throughput APIs, and serverless cold starts and WASM.