This document describes Bun's file and blob APIs, focusing on Bun.file(), the BunFile interface, and high-performance file I/O operations. These APIs provide lazy file references, efficient data handling, and seamless integration between JavaScript and native code.
For Node.js file system APIs (fs module), see File System APIs. For streaming file I/O, see Streams API.
Bun's file and blob APIs center around:
Bun.file(path) - Creates lazy file references without loading dataThe implementation is in jsc.WebCore.Blob (constructor: WebCore.Blob.constructBunFile) with type conversion utilities in src/bun.js/node/types.zig.
Sources: src/bun.js/api/BunObject.zig20 src/bun.js/node/types.zig1-133
Diagram: Bun.file() and BunFile Architecture
The BunFile interface returned by Bun.file():
needsToReadFile())Sources: src/bun.js/api/BunObject.zig20 src/bun.js/node/types.zig1-85
Bun.file(path) creates lazy file references without loading data into memory:
Implementation Flow:
Diagram: Lazy File Loading in Bun.file()
File validation timing:
Sources: src/bun.js/api/BunObject.zig20 src/bun.js/api/server.zig158-188
The BunFile returned by Bun.file() implements the standard File/Blob interface:
| Property/Method | Type | Description |
|---|---|---|
name | string | File basename |
size | number | File size in bytes (via stat) |
type | string | MIME type (inferred from extension) |
lastModified | number | Last modified timestamp (milliseconds) |
text() | Promise<string> | Read file as UTF-8 text |
arrayBuffer() | Promise<ArrayBuffer> | Read file as binary |
json() | Promise<any> | Parse file as JSON |
stream() | ReadableStream | Stream file contents |
slice(start, end) | Blob | Create sub-blob |
writer() | FileSink | Get writable stream |
Lazy loading behavior:
Memory efficiency: The file is memory-mapped for large files, avoiding full reads when possible.
Sources: src/bun.js/api/BunObject.zig20 src/bun.js/node/types.zig49-85
Bun's file APIs accept multiple input types, converted internally through the BlobOrStringOrBuffer union:
Diagram: Input Type Conversion Pipeline
Conversion modes:
fromJS): References existing memory, no copiesfromJSAsync): Copies data via toThreadSafe() for thread safetyfromJSWithEncodingValue): Handles character encodingsExample conversions:
The conversion is handled by BlobOrStringOrBuffer.fromJS() which:
value.jsType()store.ref()StringOrBuffer variantSources: src/bun.js/node/types.zig1-133 src/bun.js/node/types.zig230-339
Multiple paths lead to the same blob-based reading mechanism:
Diagram: File Reading Mechanisms
Reading strategies:
| Method | Behavior | When to Use |
|---|---|---|
text() | Full read into memory | Small text files |
arrayBuffer() | Full read as binary | Small binary files |
stream() | Incremental chunks | Large files, backpressure |
json() | Parse after full read | JSON files |
Example:
Sources: src/bun.js/api/BunObject.zig20 src/sys.zig490-508
Bun.write() provides high-performance file writing with automatic type conversion:
Write implementation:
Diagram: Bun.write() Operation Flow
Optimizations:
sendfile() syscall on Linux src/sys.zig472-488Sources: src/bun.js/api/BunObject.zig42 src/sys.zig472-508
The server routing system uses Bun.file() for static file serving:
Route types:
Validation for bundled assets happens at startup to fail fast src/bun.js/api/server.zig169-181
Bun.file() can be used with Node.js fs APIs:
The conversion from BunFile to file descriptor or path happens automatically.
Files integrate seamlessly with fetch:
Sources: src/bun.js/api/server.zig158-188 src/bun.js/node/node_fs.zig1-67
File operations support multiple character encodings via the Encoding enum:
| Encoding | Description | Example |
|---|---|---|
utf8 | UTF-8 (default) | file.text() |
utf16le | UTF-16 LE | Windows text files |
latin1 | ISO-8859-1 | Binary-as-text |
base64 | Base64 | Data URLs |
hex | Hexadecimal | Hash outputs |
Usage:
The encoding conversion is handled by Encoding.encodeWithMaxSize() and related functions src/bun.js/node/types.zig448-487
Sources: src/bun.js/node/types.zig344-493
Blobs use reference counting to share data without copying:
Diagram: Blob Store Reference Counting Lifecycle
GC integration:
protect()/unprotect() to control GCprotect() to prevent premature collection src/bun.js/node/types.zig25-32When passing data to worker threads or async operations:
Thread-safe conversions:
toThreadSafeSlice() src/bun.js/node/types.zig143-158protect() to prevent GCSources: src/bun.js/node/types.zig25-44 src/bun.js/node/types.zig143-158 src/bun.js/node/types.zig230-281
Bun minimizes memory copies through several techniques:
| Operation | Mechanism | Benefit |
|---|---|---|
| File-to-file copy | sendfile() syscall | No userspace copy src/sys.zig472-488 |
| Blob sharing | Reference counting | Single data, multiple refs |
| Large files | Memory mapping | No load into memory |
| Stream chunks | Direct slices | No intermediate buffers |
Example - zero-copy file copy:
Large files may be memory-mapped instead of loaded:
Sources: src/sys.zig472-488 src/bun.js/node/types.zig18-23
Windows requires special path handling via PathLike.sliceW():
\\?\ prefix for paths >260 chars src/bun.js/node/types.zig589-598C:\ → \\?\C:\)POSIX systems (Linux, macOS) use simpler paths:
sliceZ()MAX_PATHSources: src/bun.js/node/types.zig584-661 src/sys.zig309-334
File operations can fail at several stages:
Diagram: Error Sources in File Operations
| Error | Description | Example |
|---|---|---|
ENAMETOOLONG | Path exceeds MAX_PATH | Very long file paths |
ENOENT | File doesn't exist | Missing file |
EACCES | Permission denied | Read-only file |
EINVAL | Invalid argument | Bad encoding name |
ERR_INVALID_ARG_VALUE | Null bytes in path | Path with \0 |
Validation functions:
Valid.pathSlice() - Path length check src/bun.js/node/types.zig763-773Valid.pathBuffer() - Buffer path validation src/bun.js/node/types.zig791-805Valid.pathNullBytes() - Null byte detection src/bun.js/node/types.zig807-811Example:
Sources: src/bun.js/node/types.zig763-811 src/sys.zig302-508
Internally uses BlobOrStringOrBuffer.fromJS() to handle all input types uniformly.
Uses toThreadSafe() to ensure safe cross-thread access.
Defers I/O until data is actually accessed.
Sources: src/bun.js/node/types.zig49-85 src/bun.js/node/types.zig724-755
Refresh this wiki