| name | bun |
| description | [Applies to: **/*.{js,jsx}] Enforces modern JavaScript best practices and leverages Bun's integrated tooling for high-performance, maintainable backend services. |
| source | cursor_mdc |
bun Best Practices
Bun is our go-to runtime for high-performance JavaScript/TypeScript backend services. It's an all-in-one toolkit designed for speed and developer experience. Adhere to these guidelines to maximize Bun's potential and maintain code quality.
1. Embrace Bun's Integrated Toolchain
Bun's strength lies in its unified toolchain. Always default to Bun's built-in features over external alternatives unless a specific project requirement dictates otherwise.
✅ GOOD: Use Bun's native tools
- Package Management:
bun install for dependencies, bun add for new packages.
- Bundling:
bun build for zero-config bundling and standalone executables.
- Testing:
bun test for Jest-compatible testing, including watch mode and coverage.
- Runtime:
bun run or bun <file> for execution.
bun install
bun add zod
bun test --coverage
bun build ./src/index.ts --target=bun --outfile=./dist/server
❌ BAD: Mixing package managers or external bundlers unnecessarily
Avoid npm install or yarn add in Bun projects. Don't use Webpack or Rollup if bun build suffices.
2. Modern JavaScript Language Features
Always use current ECMAScript features (ES2015+). This improves readability, reduces bugs, and aligns with modern development.
✅ GOOD: Modern JS syntax
const API_URL = 'https://api.example.com';
let retryCount = 0;
import { serve } from 'bun';
import { z } from 'zod';
class UserService {
#users = new Map();
constructor() {
this.#users.set('1', { id: '1', name: 'Alice' });
}
getUser = (id) => {
return this.#users.get(id);
};
}
const user = new UserService().getUser('2');
const userName = user?.name ?? 'Guest';
async function () {
{
response = (url);
(!response.) {
();
}
response.();
} (error) {
.(, error);
;
}
}
configMap = ([
[, ],
[, ],
]);
data = [];
(.(data)) {
.();
}
❌ BAD: Outdated JS patterns
var API_URL = 'https://api.example.com';
const { serve } = require('bun');
function UserServiceOld() {
this.users = {};
}
UserServiceOld.prototype.getUser = function(id) { };
const count = 0;
const defaultCount = count || 10;
fetch('/api').then(res => res.json()).catch(err => console.error(err));
3. Code Organization and Structure
Maintain a clear, consistent project structure. This enhances navigability and maintainability, especially in larger applications.
✅ GOOD: Logical directory structure
.
├── src/
│ ├── api/ # HTTP route handlers
│ │ ├── users.js
│ │ └── index.js
│ ├── services/ # Business logic, data access
│ │ ├── userService.js
│ │ └── authService.js
│ ├── utils/ # Helper functions
│ │ └── validators.js
│ ├── middleware/ # Express-style middleware
│ │ └── auth.js
│ └── index.js # Main application entry point
├── tests/ # Unit and integration tests
│ ├── api.test.js
│ └── services.test.js
├── .env # Environment variables
├── bunfig.toml # Bun-specific configuration
└── package.json
4. Performance Considerations (Bun Specific)
Leverage Bun's native APIs for I/O and common tasks. They are highly optimized and significantly faster than Node.js equivalents or external libraries.
✅ GOOD: Utilize native Bun APIs
Bun.serve({
port: Bun.env.PORT || 3000,
fetch(req) {
const url = new URL(req.url);
if (url.pathname === '/') {
return new Response('Hello, Bun!');
}
if (url.pathname === '/users') {
const db = new Bun.SQLite('mydb.sqlite');
const users = db.query('SELECT * FROM users').all();
return Response.json(users);
}
return new Response('404 Not Found', { status: 404 });
},
});
const fileContent = await Bun.file('./data.json').json();
❌ BAD: Relying on Node.js-compatible but slower alternatives
import express from 'express';
const app = express();
app.get('/', (req, res) => res.send('Hello, Express!'));
app.listen(3000);
import { readFile } from 'node:fs/promises';
const content = JSON.parse(await readFile('./data.json', 'utf8'));
5. Error Handling
Implement robust error handling to prevent crashes and provide meaningful feedback. Centralize error handling for consistency.
✅ GOOD: Centralized async error handling
export function errorHandler(err, req, res, next) {
console.error(err);
const statusCode = err.statusCode || 500;
res.status(statusCode).json({
message: err.message || 'An unexpected error occurred.',
...(Bun.env.NODE_ENV === 'development' && { stack: err.stack }),
});
}
Bun.serve({
port: Bun.env.PORT || 3000,
async fetch(req) {
try {
if (req.url.includes('/error')) {
throw new Error('Simulated error!');
}
return new Response('OK');
} catch (error) {
(.({ : error. }), {
: error. || ,
: { : },
});
}
},
});
❌ BAD: Unhandled promise rejections or silent errors
async function processData() {
const data = await fetchData('/non-existent-api');
console.log(data);
}
processData();
6. Security Best Practices
Security is paramount. Always protect sensitive data and validate inputs.
✅ GOOD: Secure practices
const dbPassword = Bun.env.DB_PASSWORD;
const jwtSecret = Bun.env.JWT_SECRET;
const userSchema = z.object({
username: z.string().min(3).max(20),
email: z.string().email(),
password: z.string().min(8),
});
function validateUser(data) {
try {
return userSchema.parse(data);
} catch (error) {
throw new Error(`Validation failed: ${error.errors.map(e => e.message).join(', ')}`);
}
}
const corsHeaders = {
'Access-Control-Allow-Origin': 'https://our-frontend.com',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
: ,
};
.({
() {
(req. === ) {
(, { : corsHeaders });
}
(, { : corsHeaders });
},
});
❌ BAD: Hardcoding secrets or trusting user input
const DB_PASSWORD = 'supersecretpassword';
function createUser(data) {
console.log(data.username);
}
const corsHeaders = { 'Access-Control-Allow-Origin': '*' };
7. Testing Approaches
Use bun test as your primary test runner. Write focused unit tests and broader integration tests to ensure reliability.
✅ GOOD: Comprehensive testing with bun test
import { expect, test, describe, beforeEach } from 'bun:test';
import { UserService } from '../src/services/userService';
describe('UserService', () => {
let userService;
beforeEach(() => {
userService = new UserService();
});
test('should return a user by ID', () => {
const user = userService.getUser('1');
expect(user).toEqual({ id: '1', name: 'Alice' });
});
test('should return undefined for non-existent user', () => {
const user = userService.getUser('99');
expect(user).toBeUndefined();
});
test('should match user list snapshot', () => {
expect(userService.getAllUsers()).toMatchSnapshot();
});
});
❌ BAD: Skipping tests or using external test runners unnecessarily
Avoid relying solely on manual testing or introducing Jest/Vitest if bun test covers your needs.