bun-nextjs

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Bun Next.js

Bun Next.js

Run Next.js applications with Bun for faster development and builds.
使用Bun运行Next.js应用,以获得更快的开发与构建速度。

Quick Start

快速开始

bash
undefined
bash
undefined

Create new Next.js project with Bun

Create new Next.js project with Bun

bunx create-next-app@latest my-app cd my-app
bunx create-next-app@latest my-app cd my-app

Install dependencies

Install dependencies

bun install
bun install

Development

Development

bun run dev
bun run dev

Build

Build

bun run build
bun run build

Production

Production

bun run start
undefined
bun run start
undefined

Project Setup

项目设置

package.json

package.json

json
{
  "scripts": {
    "dev": "next dev --turbo",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "next": "^16.1.1",
    "react": "^19.2.3",
    "react-dom": "^19.2.3"
  }
}
json
{
  "scripts": {
    "dev": "next dev --turbo",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "next": "^16.1.1",
    "react": "^19.2.3",
    "react-dom": "^19.2.3"
  }
}

Use Bun as Runtime

使用Bun作为运行时

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.
json
{
  "scripts": {
    "dev": "bun --bun next dev",
    "build": "bun --bun next build",
    "start": "bun --bun next start"
  }
}
--bun
标志会强制Next.js使用Bun的运行时替代Node.js。

Configuration

配置

next.config.js

next.config.js

javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
  // Enable experimental features
  experimental: {
    // Turbopack (faster dev)
    turbo: {},
  },

  // Server-side Bun APIs
  serverExternalPackages: ["bun:sqlite"],

  // Webpack config (if needed)
  webpack: (config, { isServer }) => {
    if (isServer) {
      // Allow Bun-specific imports
      config.externals.push("bun:sqlite", "bun:ffi");
    }
    return config;
  },
};

module.exports = nextConfig;
javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
  // Enable experimental features
  experimental: {
    // Turbopack (faster dev)
    turbo: {},
  },

  // Server-side Bun APIs
  serverExternalPackages: ["bun:sqlite"],

  // Webpack config (if needed)
  webpack: (config, { isServer }) => {
    if (isServer) {
      // Allow Bun-specific imports
      config.externals.push("bun:sqlite", "bun:ffi");
    }
    return config;
  },
};

module.exports = nextConfig;

Using Bun APIs in Next.js

在Next.js中使用Bun API

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>
  );
}
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

API路由

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 });
}
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 });
}
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");
}
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");
}

Middleware

中间件

typescript
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export function middleware(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*"],
};
typescript
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export function middleware(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
undefined
bash
undefined

.env.local

.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
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

生产环境构建

bash
bun run build
bun run start
bash
bun run build
bun run start

Docker

Docker

dockerfile
FROM 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"]
dockerfile
FROM 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

Vercel

bash
undefined
bash
undefined

Install Vercel CLI

Install Vercel CLI

bun add -g vercel
bun add -g vercel

Deploy

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)
vercel

注意:Vercel的边缘运行时使用V8而非Bun。Bun API可在以下场景正常工作:
- 服务端组件(Node.js运行时)
- API路由(Node.js运行时)
- 服务端动作(Node.js运行时)

Performance Tips

性能优化提示

  1. Use Turbopack for faster dev:
    bash
    bun run dev --turbo
  2. Prefer Server Components - Less JavaScript sent to client
  3. Use Bun SQLite instead of external databases for simple apps
  4. Enable compression:
    javascript
    // next.config.js
    module.exports = {
      compress: true,
    };
  1. 使用Turbopack获得更快的开发速度:
    bash
    bun run dev --turbo
  2. 优先使用服务端组件 —— 减少发送到客户端的JavaScript体积
  3. 简单应用优先使用Bun SQLite 而非外部数据库
  4. 启用压缩
    javascript
    // next.config.js
    module.exports = {
      compress: true,
    };

Common Errors

常见错误

ErrorCauseFix
Cannot find bun:sqlite
Wrong runtimeUse
bun --bun next dev
Module not found
Missing dependencyRun
bun install
Hydration mismatch
Server/client diffCheck data fetching
Edge runtime error
Bun API on edgeUse Node.js runtime
错误原因修复方案
Cannot find bun:sqlite
运行时错误使用
bun --bun next dev
启动
Module not found
依赖缺失执行
bun install
Hydration mismatch
服务端/客户端渲染内容不一致检查数据获取逻辑
Edge runtime error
在边缘运行时使用Bun API切换为Node.js运行时

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
当遇到以下场景时加载
references/app-router.md
  • App Router相关模式
  • 路由分组
  • 并行路由
当遇到以下场景时加载
references/caching.md
  • 数据缓存策略
  • 重新验证模式
  • 静态生成