Bun Module System
Bun supports multiple module systems, including ES Modules (ESM), CommonJS (CJS), and Bun's own module resolution. This chapter introduces Bun's module system and its features.
ES Modules (ESM)
ES Modules are JavaScript's standard module system, and the recommended way to use Bun.
Exporting Modules
typescript
// math.ts
// Named exports
export const PI = 3.14159;
export function add(a: number, b: number): number {
return a + b;
}
export function multiply(a: number, b: number): number {
return a * b;
}
// Default export
export default class Calculator {
add(a: number, b: number) {
return a + b;
}
subtract(a: number, b: number) {
return a - b;
}
}Importing Modules
typescript
// main.ts
// Import default export
import Calculator from "./math";
// Import named exports
import { PI, add, multiply } from "./math";
// Import all and namespace
import * as math from "./math";
// Mixed import
import Calculator, { PI, add } from "./math";
// Use
const calc = new Calculator();
console.log(calc.add(2, 3));
console.log(add(2, 3));
console.log(math.PI);Dynamic Import
typescript
// Dynamic import (returns Promise)
async function loadModule() {
const math = await import("./math");
console.log(math.add(2, 3));
// Conditional import
if (process.env.NODE_ENV === "development") {
const devTools = await import("./dev-tools");
devTools.init();
}
}Re-exporting
typescript
// index.ts - Module aggregation
// Re-export all
export * from "./math";
export * from "./string";
// Re-export some
export { add, multiply } from "./math";
// Rename export
export { add as sum } from "./math";
// Re-export default export
export { default as Calculator } from "./math";CommonJS (CJS)
Bun fully supports the CommonJS module system, ensuring compatibility with the existing Node.js ecosystem.
CommonJS Exports
javascript
// utils.js
// Export single value
module.exports = function greet(name) {
return `Hello, ${name}!`;
};
// Export multiple values
module.exports = {
greet: function(name) {
return `Hello, ${name}!`;
},
farewell: function(name) {
return `Goodbye, ${name}!`;
}
};
// Use exports shortcut
exports.greet = function(name) {
return `Hello, ${name}!`;
};
exports.farewell = function(name) {
return `Goodbye, ${name}!`;
};CommonJS Imports
javascript
// main.js
// Import entire module
const utils = require("./utils");
console.log(utils.greet("Bun"));
// Destructuring import
const { greet, farewell } = require("./utils");
console.log(greet("Bun"));ESM and CJS Interoperability
Importing CJS in ESM
typescript
// cjs-module.js (CommonJS)
module.exports = {
name: "CJS Module",
greet() {
return "Hello from CJS!";
}
};
// esm-main.ts (ESM)
import cjsModule from "./cjs-module.js";
console.log(cjsModule.greet());
// Named imports also work (Bun handles automatically)
import { name, greet } from "./cjs-module.js";Importing ESM in CJS
javascript
// esm-module.ts (ESM)
export const message = "Hello from ESM!";
export default { name: "ESM Module" };
// cjs-main.js (CommonJS)
// Use dynamic import()
const loadESM = async () => {
const esmModule = await import("./esm-module.ts");
console.log(esmModule.message);
console.log(esmModule.default);
};
loadESM();Module Resolution
Resolution Order
Bun resolves modules in the following order:
- Built-in modules:
bun:*,node:* - Absolute paths:
/path/to/module - Relative paths:
./module,../module - node_modules: Search upward for node_modules
File Extensions
typescript
// Bun tries extensions in order
import { foo } from "./module";
// Attempt order:
// 1. ./module.ts
// 2. ./module.tsx
// 3. ./module.js
// 4. ./module.jsx
// 5. ./module/index.ts
// 6. ./module/index.tsx
// 7. ./module/index.js
// 8. ./module/index.jsxPath Aliases
Configure in tsconfig.json:
json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@utils/*": ["src/utils/*"]
}
}
}Using aliases:
typescript
import { Button } from "@components/Button";
import { formatDate } from "@utils/date";
import config from "@/config";Bun Built-in Modules
bun Module
typescript
// Use Bun global object directly
console.log(Bun.version);
// Or import bun module
import { $ } from "bun";
await $`echo "Hello from Bun Shell"`;Common bun:* Modules
typescript
// SQLite
import { Database } from "bun:sqlite";
// FFI (Foreign Function Interface)
import { dlopen, FFIType } from "bun:ffi";
// Testing
import { test, expect } from "bun:test";
// Password hashing
import { password } from "bun";Node.js Built-in Modules
Bun supports most Node.js built-in modules:
typescript
// File system
import fs from "fs";
import { readFile } from "fs/promises";
// Path handling
import path from "path";
// HTTP
import http from "http";
import https from "https";
// Other common modules
import os from "os";
import crypto from "crypto";
import util from "util";
import events from "events";
import stream from "stream";
import buffer from "buffer";Using node: Prefix
typescript
// Recommended to use node: prefix (more explicit)
import fs from "node:fs";
import path from "node:path";
import { Buffer } from "node:buffer";Importing JSON and Other Files
Importing JSON
typescript
// Import JSON directly
import config from "./config.json";
console.log(config.apiUrl);
// Type-safe JSON import
import packageJson from "./package.json" with { type: "json" };
console.log(packageJson.version);Importing Text Files
typescript
// Import as string
import readme from "./README.md" with { type: "text" };
console.log(readme);Importing TOML
typescript
// Import TOML config
import config from "./config.toml";
console.log(config.database.host);Module Caching
Caching Mechanism
Bun caches loaded modules; each module is executed only once:
typescript
// counter.ts
let count = 0;
export function increment() {
return ++count;
}
// main.ts
import { increment } from "./counter";
import { increment as inc } from "./counter";
console.log(increment()); // 1
console.log(inc()); // 2 (same module instance)Clearing Cache
typescript
// May need to clear cache in tests
delete require.cache[require.resolve("./module")];Circular Dependencies
Handling Circular Dependencies
typescript
// a.ts
import { b } from "./b";
export const a = "A";
console.log("a.ts loaded, b =", b);
// b.ts
import { a } from "./a";
export const b = "B";
console.log("b.ts loaded, a =", a);
// main.ts
import { a } from "./a";
// Output:
// b.ts loaded, a = undefined
// a.ts loaded, b = BAvoiding Circular Dependencies
typescript
// Method 1: Lazy import
export function getA() {
const { a } = require("./a");
return a;
}
// Method 2: Refactor code, extract shared module
// shared.ts - Shared code
// a.ts - imports shared
// b.ts - imports sharedpackage.json Configuration
type Field
json
{
"type": "module" // Use ESM
}json
{
"type": "commonjs" // Use CJS (default)
}exports Field
json
{
"name": "my-package",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
},
"./utils": {
"import": "./dist/utils.mjs",
"require": "./dist/utils.cjs"
}
}
}Conditional Exports
json
{
"exports": {
".": {
"bun": "./src/index.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs",
"default": "./dist/index.js"
}
}
}Bun will prioritize the bun condition.
Summary
This chapter covered:
- ✅ ES Modules import/export syntax
- ✅ CommonJS module system
- ✅ ESM and CJS interoperability
- ✅ Module resolution rules and path aliases
- ✅ Bun and Node.js built-in modules
- ✅ JSON, TOML, and other file imports
- ✅ Module caching and circular dependency handling
Next Steps
Continue reading TypeScript Support to learn about Bun's native TypeScript support.