AgentSkillsCN

use-bun

针对 TypeScript 项目的 Bun 首选开发模式。当您需要评估 Node.js 项目是否存在迁移机会、启动新项目、分析 npm 依赖项,或减少 package.json 文件的冗余时,可选用此模式。当用户提到 npm、yarn、pnpm、Node.js 迁移、依赖审计或包优化时,该模式便会自动触发。

SKILL.md
--- frontmatter
name: use-bun
description: Bun-first development patterns for TypeScript projects. Use when auditing Node.js projects for migration opportunities, starting new projects, evaluating npm dependencies, or reducing package.json bloat. Triggers on mentions of npm, yarn, pnpm, Node.js migration, dependency audit, or package optimization.
metadata:
  version: 1.1.0
  category: development

Use Bun

Bun-first philosophy: prefer native APIs over external packages.

<when_to_use>

  • Auditing existing projects for Bun migration opportunities
  • Starting new TypeScript projects
  • Evaluating whether to add a dependency
  • Reviewing code that uses Node.js APIs
  • Cleaning up package.json bloat

Boundary: This skill covers when to use Bun and what it replaces. For detailed Bun API patterns and implementation examples, load the outfitter:bun-dev skill instead.

</when_to_use>

CLI Commands

Use Bun directly instead of Node.js tooling:

Instead ofUse
node file.ts or ts-node file.tsbun file.ts
jest or vitestbun test
webpack or esbuild (CLI)bun build
npm install / yarn / pnpmbun install
npm run scriptbun run script
npx packagebunx package
nodemonbun --watch
node --env-file=.envbun (auto-loads .env)

Decision Framework

Before adding a dependency, follow this hierarchy:

code
Need functionality
│
├─► Does Bun have a built-in API?
│   └─► YES → Use it directly
│
├─► Can you wrap a Bun primitive?
│   └─► YES → Thin abstraction over Bun API
│
└─► External package (last resort)
    └─► Document why Bun couldn't do it

Evaluation Checklist

  1. Check Bun docs first: https://bun.sh/docs
  2. Search for Bun. or bun: in docs
  3. Test if Node.js API you're using has faster Bun equivalent
  4. If adding package, verify Bun doesn't cover it natively

When Packages Are Justified

  • Framework-level abstractions (Hono, TanStack Router)
  • Domain-specific logic (Zod schemas, date-fns)
  • Protocol implementations Bun doesn't cover
  • Battle-tested crypto beyond basic hashing

Document exceptions with a code comment:

typescript
// Using date-fns: Bun has no date manipulation APIs
import { format, addDays } from 'date-fns';

Quick Reference

Bun APIs organized by category. Check these before reaching for npm.

Testing

Bun APIReplaces
bun:testjest, vitest, mocha
expect()chai, expect.js
typescript
import { describe, test, expect } from 'bun:test';

Database & Storage

Bun APIReplaces
bun:sqlitebetter-sqlite3, sql.js
Bun.sqlpg, postgres.js, mysql2
Bun.redisioredis, redis
Bun.s3@aws-sdk/client-s3
typescript
import { Database } from 'bun:sqlite';
const client = Bun.redis();
const bucket = Bun.s3('my-bucket');

Networking

Bun APIReplaces
Bun.listen()net.createServer
Bun.connect()net.connect
Bun.udpSocket()dgram.createSocket
Bun.dnsdns.lookup

HTTP

Bun APIReplaces
Bun.serve()express, fastify, http
Bun.fetch()node-fetch, axios, got
typescript
Bun.serve({ port: 3000, fetch: (req) => new Response('ok') });

Shell & Process

Bun APIReplaces
Bun.$execa, shelljs, zx
Bun.spawn()child_process.spawn
Bun.spawnSync()child_process.spawnSync
typescript
import { $ } from 'bun';
await $`ls -la`;

File System

Bun APIReplaces
Bun.file()fs.readFile, fs-extra
Bun.write()fs.writeFile
file.exists()fs.existsSync
file.stream()fs.createReadStream
typescript
const content = await Bun.file('./data.json').json();
await Bun.write('./out.txt', content);

Utilities

Bun APIReplaces
Bun.password.hash()bcrypt, argon2
Bun.hash()xxhash, murmur, crc32
Bun.CryptoHashercrypto.createHash
Bun.Globglob, fast-glob, minimatch
Bun.semversemver
Bun.YAML.parse()js-yaml, yaml
Bun.TOML.parse()toml
Bun.gzipSync()zlib, pako
Bun.zstdCompressSync()zstd-codec
Bun.Archivetar, archiver
Bun.sleep()delay, timers-promises
Bun.deepEquals()lodash.isEqual, deep-equal
Bun.escapeHTML()escape-html
Bun.stringWidth()string-width
Bun.Cookiecookie, tough-cookie
Bun.randomUUIDv7()uuid
Bun.which()which
typescript
const hash = await Bun.password.hash(password, { algorithm: 'argon2id' });
const glob = new Bun.Glob('**/*.ts');
const valid = Bun.semver.satisfies('1.2.3', '>=1.0.0');

Bundling

Bun APIReplaces
Bun.build()esbuild, rollup, webpack
bun build --compilepkg, nexe
bash
bun build ./index.ts --outfile dist/bundle.js --minify

Frontend Development

Bun.serve() supports HTML imports with automatic bundling. No Vite/Webpack needed.

typescript
// server.ts
import index from "./index.html";

Bun.serve({
  routes: {
    "/": index,
    "/api/data": (req) => Response.json({ ok: true }),
  },
  development: { hmr: true, console: true },
});

HTML files can import .tsx/.jsx/.ts directly:

html
<!-- index.html -->
<html>
  <body>
    <div id="root"></div>
    <script type="module" src="./app.tsx"></script>
  </body>
</html>

Run with hot reloading:

bash
bun --hot server.ts

Audit Command

Scan a codebase for Bun migration opportunities using the bundled audit script.

bash
# From the skill directory (or adjust path as needed)
bun ./scripts/audit-bun-usage.ts [path]

# JSON output (default) - pipe to jq, use in CI
bun ./scripts/audit-bun-usage.ts ./my-project

# Markdown output - human readable
bun ./scripts/audit-bun-usage.ts ./my-project --format=md

The audit identifies:

  • npm packages replaceable by Bun built-ins
  • Node.js imports with Bun equivalents
  • Config files for tools Bun replaces
  • Files already using Bun APIs (positive signal)

Common Migrations

From Express/Fastify

typescript
// Before: Express
import express from 'express';
const app = express();
app.get('/', (req, res) => res.send('ok'));
app.listen(3000);

// After: Bun.serve + Hono
import { Hono } from 'hono';
const app = new Hono().get('/', (c) => c.text('ok'));
Bun.serve({ port: 3000, fetch: app.fetch });

From Jest/Vitest

typescript
// Before: Jest
import { describe, it, expect } from '@jest/globals';

// After: bun:test (drop-in compatible)
import { describe, it, expect } from 'bun:test';

From better-sqlite3

typescript
// Before
import Database from 'better-sqlite3';

// After (same API)
import { Database } from 'bun:sqlite';

From bcrypt

typescript
// Before
import bcrypt from 'bcrypt';
const hash = await bcrypt.hash(password, 10);

// After
const hash = await Bun.password.hash(password, { algorithm: 'argon2id' });

From execa/shelljs

typescript
// Before
import { execa } from 'execa';
const { stdout } = await execa('ls', ['-la']);

// After
import { $ } from 'bun';
const result = await $`ls -la`;
console.log(result.text());
<rules>

ALWAYS:

  • Check Bun docs before adding any dependency
  • Use Bun.file/Bun.write over fs module
  • Use bun:test for testing (Jest-compatible)
  • Use bun:sqlite for SQLite (better-sqlite3 compatible)
  • Use Bun.password for password hashing
  • Use Bun.$ for shell commands

NEVER:

  • Add packages that duplicate Bun built-ins without documenting why
  • Use node-fetch when Bun.fetch exists
  • Use bcrypt when Bun.password exists
  • Use fs when Bun.file/Bun.write exists
  • Use child_process when Bun.$/Bun.spawn exists

DOCUMENT:

  • Why a package is needed when Bun alternative exists
  • Bun limitations encountered (helps track what to migrate later)
  • Exceptions in code comments for future audits
</rules> <references>

Related skills:

  • outfitter:bun-dev — Detailed Bun API patterns, implementation examples, testing strategies
  • outfitter:typescript-dev — TypeScript patterns for Bun projects, strict typing, Zod validation
</references>