Bun + Vite + Reactbuild

Why Bun & Vite & React for TypeScript

The modern stack: fast runtime, instant dev server, proven UI library

v1.1·12 min read·Kenneth Pernyér
bunvitereacttypescripttoolingdx

The Problem

The JavaScript ecosystem accumulated layers of tooling over two decades. A typical Node.js + React project required:

  • A runtime (Node.js)
  • A package manager (npm, yarn, or pnpm)
  • A bundler (webpack)
  • A dev server (webpack-dev-server)
  • A test runner (Jest)
  • A TypeScript compiler (tsc or babel)
  • React refresh plugins
  • CSS processing (PostCSS, sass-loader)

Each tool has its own configuration, its own quirks, its own update cycle. The surface area for breakage is enormous. When something fails, you're debugging tool interactions, not your actual code.

The modern stack collapses this complexity.

Bun replaces Node.js, npm, Jest, and ts-node—one tool for runtime, packages, testing, and TypeScript execution. Vite replaces webpack and its ecosystem—instant dev server, optimized production builds, React Fast Refresh out of the box. React remains React—the UI library that won.

Together, they eliminate configuration hell while maximizing development velocity.

Current Options

OptionProsCons
Node.js + Webpack + ReactThe legacy stack. Still works, still painful.
  • Battle-tested in production
  • Massive ecosystem of plugins
  • Extensive documentation
  • Handles any edge case
  • 5+ config files to maintain
  • Slow dev server startup (30+ seconds)
  • Complex webpack configuration
  • Slow npm install in CI
Node.js + Vite + ReactModern build tooling, legacy runtime.
  • Instant dev server startup
  • Excellent React HMR
  • Simple configuration
  • Mature and stable
  • Still need separate test runner
  • npm install still slow
  • Node.js startup overhead
  • Multiple tools to coordinate
Bun + Vite + ReactThe convergent stack. Each tool does what it does best.
  • Bun: fast runtime, packages, tests, TypeScript
  • Vite: instant dev server, React HMR, production builds
  • React: proven UI patterns, huge ecosystem
  • Minimal configuration, maximum velocity
  • Bun is younger than Node.js
  • Some Node.js APIs not yet in Bun
  • Two tools instead of one (but each is excellent)

Future Outlook

Each tool in this stack has won its category:

Bun is the fastest JavaScript runtime. It's eating Node.js's lunch for new projects. The all-in-one approach (runtime + package manager + test runner + TypeScript) eliminates tool coordination overhead.

Vite won the bundler wars. Webpack is legacy. Vite's native ES modules approach means instant dev server startup regardless of project size. React Fast Refresh just works.

React won the UI library wars. The ecosystem, the patterns, the hiring pool—React is infrastructure now.

The question isn't whether to use this stack—it's why you'd choose anything else for a new TypeScript web application.

Why not Bun's bundler for everything?

Bun includes a bundler, and it's improving rapidly. For simple builds, it works. But Vite's dev server with React Fast Refresh is specifically optimized for the React development experience. The HMR is faster, the error overlay is better, the plugin ecosystem is richer.

Use the right tool for each job: Bun for runtime and testing, Vite for dev server and builds.

Our Decision

Why we chose this

  • Sub-second feedback loopsBun starts in milliseconds. Vite serves changes instantly. React Fast Refresh preserves component state. Change code, see results immediately.
  • 10x faster CIbun install is dramatically faster than npm. bun test runs faster than Jest. Vite builds faster than webpack. CI minutes become CI seconds.
  • Minimal configurationVite config is ~10 lines. Bun needs no config for TypeScript. React works out of the box. Compare to webpack.config.js nightmares.
  • Native TypeScript everywhereBun runs TypeScript directly. Vite transforms it instantly. No separate compilation step. No tsconfig complexity for basic usage.
  • Production-readyVite production builds use Rollup—mature, optimized, tree-shaken. Bun runs the result in production with excellent performance.

×Trade-offs we accept

  • Bun maturityBun is younger than Node.js. Some edge cases may surprise you. We accept this trade-off for the velocity gains.
  • Two tools, not oneBun has a bundler, but Vite's React DX is better. We use both rather than forcing one tool to do everything poorly.
  • Windows supportBun's Windows support is newer. Our development happens on macOS/Linux. Verify if Windows is critical for you.

Motivation

We chose this stack because each component is best-in-class at its job:

Bun gives us fast package installation (CI went from 2 minutes to 15 seconds), fast test execution (suite runs in 3 seconds, not 30), and native TypeScript without compilation.

Vite gives us the best React development experience available. Instant startup, instant HMR, preserved component state during edits. When AI generates a component, we see the result before our finger leaves the key.

React gives us a proven UI model, massive ecosystem, and the largest talent pool. We're not fighting the library; we're building on solid foundations.

The combination is multiplicative. Fast packages + fast dev server + fast tests = development velocity that compounds.

Recommendation

Start a new React + TypeScript project:

# Install Bun
curl -fsSL https://bun.sh/install | bash

# Create Vite + React project
bun create vite my-app --template react-ts
cd my-app

# Install dependencies (fast!)
bun install

# Start dev server
bun run dev

Project structure:

  • bun install for dependencies (replaces npm)
  • bun run dev to start Vite dev server
  • bun test for tests (replaces Jest)
  • bun run build for Vite production build
  • bun run preview to preview production build

Key insight: Bun runs Vite. You get Bun's speed for everything except the dev server and bundling, where Vite's React-specific optimizations shine.

Examples

vite.config.tstypescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
        },
      },
    },
  },
});

Complete Vite config for React + TypeScript. Path aliases, vendor chunking, and React Fast Refresh—all in 20 lines.

src/App.test.tsxtypescript
import { expect, test, mock } from 'bun:test';
import { render, screen } from '@testing-library/react';
import { App } from './App';

test('renders welcome message', () => {
  render(<App />);
  expect(screen.getByText(/welcome/i)).toBeDefined();
});

test('fetches user data', async () => {
  const mockFetch = mock(() =>
    Promise.resolve({ json: () => ({ name: 'Test User' }) })
  );
  globalThis.fetch = mockFetch;

  render(<App />);

  // Bun's test runner is Jest-compatible but faster
  expect(mockFetch).toHaveBeenCalled();
});

Bun's test runner with React Testing Library. Jest-compatible API, but tests run 10x faster. No separate Jest config needed.

package.jsonjson
{
  "name": "my-app",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "test": "bun test",
    "typecheck": "tsc --noEmit"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@types/react": "^18.2.0",
    "@vitejs/plugin-react": "^4.0.0",
    "typescript": "^5.0.0",
    "vite": "^5.0.0"
  }
}

Minimal package.json. Bun handles installation and testing. Vite handles dev server and builds. No webpack, no Jest, no babel.

Related Articles

Stockholm, Sweden

Version 1.1

Kenneth Pernyér signature