Bun Runtime with Nuxt 4
Bun promises faster installs, native TypeScript, and better performance. Nuxt 4 supports it. But the reality is more nuanced.
The Promise
Bun offers significant improvements over Node.js:
- 4x faster package installs — Native resolver, no intermediate steps
- Native TypeScript — No transpilation required
- Faster HTTP — Up to 2.8x more requests per second
- Single binary — Runtime, bundler, package manager in one
Current Status
Nuxt officially supports Bun since version 3.6. Nuxt 4 continues this support through Nitro's Bun preset.
The catch: support does not mean parity. Several edge cases break.
Recommended Versions
[email protected] with [email protected]
Latest stable as of January 2026. Bun joined Anthropic in December 2025 — expect tighter integration with AI tooling.
Avoid Bun 1.2.14 through 1.2.20. Socket connection errors plague these versions with Nuxt.
Note: Nuxt 3 reaches end of maintenance at the end of January 2026. Migrate to Nuxt 4 if you haven't already.
Configuration
Basic Setup
Initialize a new project:
bunx nuxi init my-app
cd my-app
bun install
Development
Two modes exist:
# Uses Node.js runtime (default)
bun run dev
# Uses Bun runtime
bun --bun run dev
The --bun flag forces the Bun runtime. Without it, the Nuxt CLI falls back to Node.js.
Production Build
Configure the Nitro preset in nuxt.config.ts:
export default defineNuxtConfig({
compatibilityDate: '2025-01-14',
nitro: {
preset: 'bun'
}
})
Or set via environment variable:
NITRO_PRESET=bun bun run build
Why the Preset Matters
The default node-server preset does not bundle Bun-specific exports. If your app uses packages with Bun-specific features (like bun:sqlite), production builds break without the Bun preset.
Known Issues
Socket Errors on Windows
ENOENT: no such file or directory, listen '\\.\pipe\nuxt-dev-XXXX.sock'
Bun 1.2.14–1.2.20 fails on Windows with Nuxt 4. The workaround: use WSL.
HMR Breaks with Bun Runtime
When using bun --bun run dev, WebSocket connections fail:
WebSocket connection to 'ws://localhost:24678/_nuxt/' failed
[vite] server connection lost
Fix by enabling polling:
// nuxt.config.ts
export default defineNuxtConfig({
vite: {
server: {
watch: {
usePolling: true,
interval: 100
}
}
}
})
400 Errors on Non-GET Requests
All POST, PUT, DELETE requests return 400 in dev mode when using the Bun runtime or preset.
This only affects development. Production builds work correctly.
fsevents Crashes on macOS
Assertion failed: function fse_dispatch_event, file fsevents.c, line 151
Affects macOS with Nuxt 3.16.0+ and Bun 1.2.4+. Workaround: run without the --bun flag.
Memory Leak in Dev Mode
When running nuxt dev with compatibilityVersion: 4, memory usage climbs steadily. Starts at ~500MB, reaches 6GB after 5 minutes.
Only affects Bun runtime in development. Production builds and Node.js runtime work fine.
Tracked in GitHub Issue #16219.
crossws Module Error
RollupError: This module cannot be imported in server runtime.
[importing crossws/dist/adapters/bun.mjs]
Add to your config:
export default defineNuxtConfig({
nitro: {
preset: 'bun',
rollupConfig: {
external: ['bun']
}
}
})
Bun SQLite
Bun ships with a native SQLite driver via bun:sqlite. Zero dependencies, fast, and built-in.
Using bun:sqlite in Server Routes
// server/api/users.get.ts
import { Database } from 'bun:sqlite'
const db = new Database('mydb.sqlite')
export default defineEventHandler(() => {
return db.query('SELECT * FROM users').all()
})
The Catch
This only works when:
- Running with Bun runtime (
bun --bun run devor production with Bun preset) - Building with
nitro.preset: 'bun'
Without the Bun preset, production builds use Node.js and bun:sqlite imports fail.
Configuration for bun:sqlite
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
preset: 'bun',
rollupConfig: {
external: ['bun:sqlite']
}
}
})
Nuxt Content and SQLite
Nuxt Content v3 uses SQLite internally. This creates friction with Bun.
The Problem
Nuxt Content depends on better-sqlite3 for Node.js. This native module doesn't compile for Bun — different ABI versions.
Error: The module 'better_sqlite3' was compiled against a different Node.js ABI version
Current Status
Nuxt Content should auto-detect Bun and use bun:sqlite instead of better-sqlite3. In practice, detection fails in some scenarios.
Tracked in GitHub Issue #2936 and Issue #3118.
Workarounds
Option 1: Install with npm, run with Bun
npm install
bun run dev
This bypasses the better-sqlite3 compilation issue during install.
Option 2: Use Node.js native SQLite (v22.5+)
If you're on Node.js 22.5+, enable experimental native SQLite:
// nuxt.config.ts
export default defineNuxtConfig({
content: {
experimental: {
nativeSqlite: true
}
}
})
Option 3: Skip Nuxt Content for Bun projects
If you need full Bun runtime in production, consider alternatives:
- Static markdown with
@nuxt/contentin prerender mode - Custom markdown parsing with
markedorremark - External CMS (Strapi, Sanity, Contentful)
Production Builds
Nuxt Content works in production builds if you prerender content at build time. The SQLite database gets bundled into the output.
// nuxt.config.ts
export default defineNuxtConfig({
content: {
database: {
type: 'sqlite',
filename: ':memory:'
}
},
routeRules: {
'/blog/**': { prerender: true }
}
})
Module Compatibility
Some Nuxt modules have known issues with Bun:
| Module | Issue |
|---|---|
| @nuxt/content | better-sqlite3 ABI mismatch |
| @prisma/nuxt | Freezes during client generation |
| @nuxtjs/storybook | Fails to detect Bun as package manager |
| nuxt-modules/supabase | Installation errors |
| wrangler/nitro-cloudflare-dev | Fails with Bun |
Prisma Workaround
Delete bun.lockb before first dev run:
rm bun.lockb
bun install
bun run dev
Performance Reality
Benchmarks Look Great
| Metric | Bun | Node.js | Improvement |
|---|---|---|---|
| HTTP Requests/sec | ~180,000 | ~65,000 | 2.8x |
| Package Install | 4.2x faster | Baseline | 4.2x |
| TypeScript Transpile | 2.8x faster | Baseline | 2.8x |
Production Reality
Hello-world benchmarks show dramatic improvements. Standard CRUD operations show comparable performance.
Cold-start time in serverless can be higher for Bun. Memory usage may increase in some scenarios.
Test your actual workload. Benchmarks lie.
When to Use Bun
Good Candidates
- Greenfield projects — Native TypeScript, faster feedback
- Side projects — Speed compounds when iterating
- CI/CD pipelines — 4x faster package installs matter
- Serverless deployments — Lower cold-start latency
Stick with Node.js
- Large enterprise codebases — Migration rarely pays off
- Heavy native module usage — Better compatibility
- Windows development — Known socket issues
- Maximum stability required — Node.js has decades of battle-testing
Production Checklist
Before Deployment
- Lock Bun version in
package.json:
{
"packageManager": "[email protected]"
}
- Test all HTTP methods work
- Build locally first —
NITRO_PRESET=bun bun run build - Run the production build —
bun run .output/server/index.mjs
Docker Configuration
# Build Stage
FROM oven/bun:1-alpine AS build
WORKDIR /app
COPY package.json bun.lock* ./
RUN bun install --frozen-lockfile --ignore-scripts
COPY . .
ENV NITRO_PRESET=bun
RUN bun run build
# Production Stage
FROM oven/bun:1-alpine AS production
WORKDIR /app
RUN addgroup --system --gid 1001 nuxt \
&& adduser --system --uid 1001 nuxt
COPY --from=build --chown=nuxt:nuxt /app/.output ./.output
USER nuxt
ENV HOST=0.0.0.0
ENV PORT=3000
EXPOSE 3000
CMD ["bun", "--bun", "run", ".output/server/index.mjs"]
Environment Variables
| Variable | Description |
|---|---|
PORT or NITRO_PORT | Server port (default: 3000) |
HOST or NITRO_HOST | Server host (default: 0.0.0.0) |
Note: NITRO_HOST may not work with the Bun preset. Only NITRO_PORT is reliable.
Testing Setup
Vitest Configuration
// vitest.config.ts
import { defineVitestConfig } from '@nuxt/test-utils/config'
export default defineVitestConfig({
test: {
environment: 'nuxt',
environmentOptions: {
nuxt: {
domEnvironment: 'happy-dom'
}
}
}
})
Running Tests
bun run test
bun run test:e2e
Practical Recommendation
Use Bun as a package manager. Run development with Node.js. Deploy production with the Bun preset.
# Install with Bun (fast)
bun install
# Develop with Node.js (stable)
bun run dev
# Build for Bun runtime
NITRO_PRESET=bun bun run build
# Run production
bun run .output/server/index.mjs
This approach gives you faster installs without the development instability.
Summary
Bun with Nuxt 4 works. It is not seamless.
- Use Bun 1.3.6 with Nuxt 4.2.2 (latest stable)
- Set
nitro.preset: 'bun'for production - Avoid
--bunflag in development if you hit issues - Test all HTTP methods before deploying
- Use WSL on Windows
- Watch for memory leaks in long dev sessions
The performance gains are real. The edge cases are also real. Know both before committing.
References
Nuxt 4 Documentation
nuxt.com — Official installation and deployment guides
Bun + Nuxt Guide
bun.com — Official Bun documentation for Nuxt
Nitro Bun Runtime
nitro.build — Nitro preset documentation
GitHub Issue #32875
github.com — Unable to run Nuxt 4 on Bun tracking issue
GitHub Issue #21762
github.com — Bun version compatibility tracking
GitHub Issue #16219
github.com — Memory leak in dev mode
GitHub Issue #31249
github.com — HMR breaks with Bun runtime
GitHub Issue #2936
github.com — Nuxt Content better-sqlite3 doesn't work with Bun
GitHub Issue #3118
github.com — bunsqlite polyfills regression