Bun Next.js
Run Next.js applications with Bun for faster development and builds.
Quick Start
bash# Create new Next.js project with Bun bunx create-next-app@latest my-app cd my-app # Install dependencies bun install # Development bun run dev # Build bun run build # Production bun run start
Secure Installation
Scaffolding tools like bunx create-next-app download and execute remote code. Multiple install contexts (local, Docker) require pinning versions in both. Before running, follow supply chain security best practices:
- Block post-install scripts — Bun disables them by default; allow specific packages via
trustedDependenciesinpackage.json - Cooldown period — Configure
minimumReleaseAgeinbunfig.tomlto wait 7 days for new versions - Audit before installing — Run
socket package score npm <pkg>or usesocket npm install <pkg>to check packages
Load the dependency-upgrade skill for full security configuration including Socket CLI integration, cooldown setup, lockfile validation, and CI enforcement.
Project Setup
package.json
json{ "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "eslint ." }, "dependencies": { "next": "^16.2.0", "react": "^19.2.0", "react-dom": "^19.2.0" } }
Use Bun as Runtime
json{ "scripts": { "dev": "bun --bun next dev", "build": "bun --bun next build", "start": "bun --bun next start" } }
The --bun flag forces Next.js to use Bun's runtime instead of Node.js.
Configuration
next.config.js
javascript/** @type {import('next').NextConfig} */ const nextConfig = { // Turbopack is the default bundler in Next.js 16 (top-level, not under experimental) turbopack: {}, // Server-side Bun APIs serverExternalPackages: ["bun:sqlite"], // Note: a `webpack` key is no longer supported in Next.js 16 — Turbopack is the // default bundler and a `webpack` config will fail `next build`. Bun-specific // imports (`bun:sqlite`, `bun:ffi`) are handled via `serverExternalPackages` // above. If you truly need the webpack bundler, run `next build --webpack`. }; module.exports = nextConfig;
Using Bun APIs in Next.js
Server Components
typescript// app/page.tsx (Server Component) import { Database } from "bun:sqlite"; export default async function Home() { const db = new Database("data.sqlite"); const users = db.query("SELECT * FROM users").all(); db.close(); return ( <div> {users.map((user) => ( <p key={user.id}>{user.name}</p> ))} </div> ); }
API Routes
typescript// app/api/users/route.ts import { Database } from "bun:sqlite"; export async function GET() { const db = new Database("data.sqlite"); const users = db.query("SELECT * FROM users").all(); db.close(); return Response.json(users); } export async function POST(request: Request) { const body = await request.json(); const db = new Database("data.sqlite"); db.run("INSERT INTO users (name) VALUES (?)", [body.name]); db.close(); return Response.json({ success: true }); }
File Operations
typescript// app/api/files/route.ts export async function GET() { const file = Bun.file("./data/config.json"); const config = await file.json(); return Response.json(config); } export async function POST(request: Request) { const data = await request.json(); await Bun.write("./data/config.json", JSON.stringify(data, null, 2)); return Response.json({ saved: true }); }
Server Actions
typescript// app/actions.ts "use server"; import { Database } from "bun:sqlite"; import { revalidatePath } from "next/cache"; export async function createUser(formData: FormData) { const name = formData.get("name") as string; const db = new Database("data.sqlite"); db.run("INSERT INTO users (name) VALUES (?)", [name]); db.close(); revalidatePath("/users"); } export async function deleteUser(id: number) { const db = new Database("data.sqlite"); db.run("DELETE FROM users WHERE id = ?", [id]); db.close(); revalidatePath("/users"); }
Proxy (formerly Middleware)
In Next.js 16, middleware.ts is renamed to proxy.ts (the middleware name still
works but is deprecated). Proxy runs on the Node.js runtime, not the Edge runtime.
⚠️ Deploying to Cloudflare via OpenNext? Keep
middleware.ts.@opennextjs/cloudflaredoes not yet recognize theproxy.tsfilename — renaming will silently disable your middleware on Cloudflare. Until OpenNext adds support, deploy with the classicmiddleware.ts(it still works in Next 16, just deprecated upstream). This caveat does not apply to Node.js/Vercel/Bun-native deployments.
typescript// proxy.ts (renamed from middleware.ts in Next.js 16) import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; export function proxy(request: NextRequest) { // Check auth const token = request.cookies.get("token"); if (!token && request.nextUrl.pathname.startsWith("/dashboard")) { return NextResponse.redirect(new URL("/login", request.url)); } return NextResponse.next(); } export const config = { matcher: ["/dashboard/:path*"], };
Environment Variables
bash# .env.local DATABASE_URL=./data.sqlite API_SECRET=your-secret-key
typescript// Access in server components/actions const dbUrl = process.env.DATABASE_URL; const secret = process.env.API_SECRET; // Expose to client (prefix with NEXT_PUBLIC_) // .env.local NEXT_PUBLIC_API_URL=https://api.example.com
Deployment
Build for Production
bashbun run build bun run start
Docker
dockerfileFROM oven/bun:1 WORKDIR /app COPY package.json bun.lockb ./ RUN bun install --frozen-lockfile COPY . . RUN bun run build EXPOSE 3000 CMD ["bun", "run", "start"]
Vercel
bash# Install Vercel CLI bun add -g vercel # Deploy vercel
Note: Vercel's edge runtime uses V8, not Bun. Bun APIs work in:
- Server Components (Node.js runtime)
- API Routes (Node.js runtime)
- Server Actions (Node.js runtime)
Performance Tips
-
Turbopack is the default in Next.js 16 (no flag needed):
bashbun run dev -
Prefer Server Components - Less JavaScript sent to client
-
Use Bun SQLite instead of external databases for simple apps
-
Enable compression:
javascript// next.config.js module.exports = { compress: true, };
Common Errors
| Error | Cause | Fix |
|---|---|---|
Cannot find bun:sqlite | Wrong runtime | Use bun --bun next dev |
Module not found | Missing dependency | Run bun install |
Hydration mismatch | Server/client diff | Check data fetching |
Edge runtime error | Bun API on edge | Use Node.js runtime |
When to Load References
Load references/app-router.md when:
- App Router patterns
- Route groups
- Parallel routes
Load references/caching.md when:
- Data caching strategies
- Revalidation patterns
- Static generation

