Bun File I/O
Bun provides high-performance file I/O APIs that are faster and easier to use than Node.js's fs module. This chapter introduces Bun's file operations.
Bun.file() API
Creating File References
typescript
// Create file reference (does not read immediately)
const file = Bun.file("./data.txt");
// File information
console.log(file.name); // File path
console.log(file.size); // File size (bytes)
console.log(file.type); // MIME typeReading File Content
typescript
const file = Bun.file("./data.txt");
// Read as text
const text = await file.text();
console.log(text);
// Read as JSON
const jsonFile = Bun.file("./config.json");
const config = await jsonFile.json();
console.log(config);
// Read as ArrayBuffer
const buffer = await file.arrayBuffer();
// Read as Blob
const blob = await file.blob();
// Read as Uint8Array
const bytes = await file.bytes();Checking if File Exists
typescript
const file = Bun.file("./maybe-exists.txt");
// Check if file exists
const exists = await file.exists();
console.log(exists ? "File exists" : "File does not exist");Writing Files
Bun.write()
typescript
// Write text
await Bun.write("./output.txt", "Hello, Bun!");
// Write JSON
await Bun.write("./data.json", JSON.stringify({ name: "Bun" }, null, 2));
// Write binary data
const bytes = new Uint8Array([72, 101, 108, 108, 111]);
await Bun.write("./binary.bin", bytes);
// Write Response object
const response = await fetch("https://example.com/image.png");
await Bun.write("./image.png", response);
// Write Blob
const blob = new Blob(["Hello World"], { type: "text/plain" });
await Bun.write("./blob.txt", blob);Write Options
typescript
// Append mode
const writer = Bun.file("./log.txt").writer();
writer.write("First line\n");
writer.write("Second line\n");
await writer.end();Streaming Read/Write
Read Stream
typescript
const file = Bun.file("./large-file.txt");
// Get readable stream
const stream = file.stream();
// Use for await to read chunks
for await (const chunk of stream) {
console.log("Read chunk:", chunk.length, "bytes");
}Write Stream
typescript
const file = Bun.file("./output.txt");
const writer = file.writer();
// Write data
writer.write("First line\n");
writer.write("Second line\n");
writer.write(new Uint8Array([65, 66, 67]));
// Complete writing
await writer.end();Pipe Operations
typescript
// Copy from one file to another
const source = Bun.file("./source.txt");
const dest = Bun.file("./dest.txt");
await Bun.write(dest, source);Directory Operations
Reading Directories
typescript
import { readdir, readdirSync } from "node:fs/promises";
// Read directory asynchronously
const files = await readdir("./src");
console.log(files);
// Include file type information
const entries = await readdir("./src", { withFileTypes: true });
for (const entry of entries) {
console.log(
entry.name,
entry.isDirectory() ? "directory" : "file"
);
}Using Bun's Glob
typescript
// Use glob to match files
const glob = new Bun.Glob("**/*.ts");
// Iterate over matched files
for await (const file of glob.scan("./src")) {
console.log(file);
}
// Get all matched files
const files = await Array.fromAsync(glob.scan("./src"));
console.log(files);Creating Directories
typescript
import { mkdir } from "node:fs/promises";
// Create directory
await mkdir("./new-folder");
// Create recursively
await mkdir("./a/b/c", { recursive: true });Deleting Directories
typescript
import { rmdir, rm } from "node:fs/promises";
// Delete empty directory
await rmdir("./empty-folder");
// Recursive delete (includes contents)
await rm("./folder-with-content", { recursive: true });File Information
Getting File Status
typescript
import { stat, lstat } from "node:fs/promises";
const stats = await stat("./file.txt");
console.log({
size: stats.size,
isFile: stats.isFile(),
isDirectory: stats.isDirectory(),
isSymbolicLink: stats.isSymbolicLink(),
createdTime: stats.birthtime,
modifiedTime: stats.mtime,
accessTime: stats.atime,
});Using Bun.file() to Get Information
typescript
const file = Bun.file("./file.txt");
console.log({
path: file.name,
size: file.size,
type: file.type,
lastModified: file.lastModified,
});File Path Operations
path Module
typescript
import path from "node:path";
// Join paths
const fullPath = path.join("./src", "utils", "helper.ts");
// "./src/utils/helper.ts"
// Resolve to absolute path
const absolute = path.resolve("./file.txt");
// "/Users/xxx/project/file.txt"
// Get directory name
const dir = path.dirname("/path/to/file.txt");
// "/path/to"
// Get base name
const base = path.basename("/path/to/file.txt");
// "file.txt"
// Get extension
const ext = path.extname("/path/to/file.txt");
// ".txt"
// Parse path
const parsed = path.parse("/path/to/file.txt");
// { root: '/', dir: '/path/to', base: 'file.txt', ext: '.txt', name: 'file' }Special Paths
typescript
// Current working directory
console.log(process.cwd());
// Current file directory
console.log(import.meta.dir);
// Current file path
console.log(import.meta.path);
// Main module directory
console.log(Bun.main);File Copy and Move
Copying Files
typescript
import { copyFile } from "node:fs/promises";
// Use Node.js API
await copyFile("./source.txt", "./dest.txt");
// Use Bun.write
const source = Bun.file("./source.txt");
await Bun.write("./dest.txt", source);Moving/Renaming Files
typescript
import { rename } from "node:fs/promises";
// Rename
await rename("./old-name.txt", "./new-name.txt");
// Move file
await rename("./file.txt", "./folder/file.txt");Temporary Files
Creating Temporary Files
typescript
import { tmpdir } from "node:os";
import path from "node:path";
// Get temp directory
const tempDir = tmpdir();
// Create temp file
const tempFile = path.join(tempDir, `temp-${Date.now()}.txt`);
await Bun.write(tempFile, "temporary content");
console.log("Temp file:", tempFile);Using Bun Temporary Files
typescript
// Bun automatically creates temp file
const tempFile = Bun.file("/tmp/my-temp-file.txt");
await Bun.write(tempFile, "temporary data");Watching File Changes
Using Bun.watch (Experimental)
typescript
import { watch } from "node:fs";
// Watch for file changes
const watcher = watch("./src", { recursive: true }, (event, filename) => {
console.log(`File ${filename} triggered ${event} event`);
});
// Stop watching
// watcher.close();Practical Application
typescript
// Watch config file changes and reload
import { watch } from "node:fs";
let config = await loadConfig();
watch("./config.json", async (event) => {
if (event === "change") {
console.log("Config file changed, reloading...");
config = await loadConfig();
}
});
async function loadConfig() {
return Bun.file("./config.json").json();
}Practical Examples
Logger
typescript
// logger.ts
class Logger {
private logFile: string;
private writer: ReturnType<typeof Bun.file.prototype.writer> | null = null;
constructor(logFile: string) {
this.logFile = logFile;
}
private async getWriter() {
if (!this.writer) {
this.writer = Bun.file(this.logFile).writer();
}
return this.writer;
}
async log(level: string, message: string) {
const timestamp = new Date().toISOString();
const line = `[${timestamp}] [${level}] ${message}\n`;
const writer = await this.getWriter();
writer.write(line);
// Also output to console
console.log(line.trim());
}
async info(message: string) {
await this.log("INFO", message);
}
async error(message: string) {
await this.log("ERROR", message);
}
async close() {
if (this.writer) {
await this.writer.end();
this.writer = null;
}
}
}
// Usage
const logger = new Logger("./app.log");
await logger.info("Application started");
await logger.error("An error occurred");
await logger.close();File Upload Handling
typescript
// upload-server.ts
const server = Bun.serve({
port: 3000,
async fetch(request) {
if (request.method === "POST" && request.url.endsWith("/upload")) {
const formData = await request.formData();
const file = formData.get("file") as File;
if (!file) {
return new Response("No file uploaded", { status: 400 });
}
// Save file
const savePath = `./uploads/${file.name}`;
await Bun.write(savePath, file);
return Response.json({
message: "Upload successful",
filename: file.name,
size: file.size,
});
}
return new Response("Upload endpoint: POST /upload", { status: 200 });
},
});
console.log(`Upload server running at http://localhost:${server.port}`);Config File Management
typescript
// config-manager.ts
class ConfigManager<T> {
private configPath: string;
private cache: T | null = null;
constructor(configPath: string) {
this.configPath = configPath;
}
async load(): Promise<T> {
if (this.cache) return this.cache;
const file = Bun.file(this.configPath);
if (!(await file.exists())) {
throw new Error(`Config file not found: ${this.configPath}`);
}
this.cache = await file.json();
return this.cache!;
}
async save(config: T): Promise<void> {
await Bun.write(
this.configPath,
JSON.stringify(config, null, 2)
);
this.cache = config;
}
async update(updates: Partial<T>): Promise<T> {
const current = await this.load();
const updated = { ...current, ...updates };
await this.save(updated);
return updated;
}
invalidateCache(): void {
this.cache = null;
}
}
// Usage
interface AppConfig {
port: number;
debug: boolean;
apiKey: string;
}
const configManager = new ConfigManager<AppConfig>("./config.json");
const config = await configManager.load();
console.log("Current config:", config);
await configManager.update({ debug: true });Performance Comparison
Bun file I/O is much faster than Node.js:
Reading 1MB file:
Node.js fs.readFile: 5ms
Bun.file().text(): 1ms
Writing 1MB file:
Node.js fs.writeFile: 10ms
Bun.write(): 2msSummary
This chapter covered:
- ✅ Bun.file() and Bun.write() APIs
- ✅ Streaming read/write for large files
- ✅ Directory operations and glob matching
- ✅ File information and path operations
- ✅ File watching and temporary files
- ✅ Practical examples
Next Steps
Continue reading HTTP Server to learn how to create high-performance web servers with Bun.