File Io
Note — The JSTime.file and JSTime.write APIs documented on this page are heavily optimized and represent the recommended way to perform file-system tasks using JSTime. For operations that are not yet available with JSTime.file, such as mkdir, you can use JSTime’s nearly complete implementation of the node:fs module.
JSTime provides a set of optimized APIs for reading and writing files.
Reading files (JSTime.file())
Section titled “Reading files (JSTime.file())”JSTime.file(path): BunFile
Create a BunFile instance with the JSTime.file(path) function. A BunFile represents a lazily-loaded file; initializing it does not actually read the file from disk.
const foo = JSTime.file("foo.txt"); // relative to cwdfoo.size; // number of bytesfoo.type; // MIME typeThe reference conforms to the Blob interface, so the contents can be read in various formats.
const foo = JSTime.file("foo.txt");
await foo.text(); // contents as a stringawait foo.stream(); // contents as ReadableStreamawait foo.arrayBuffer(); // contents as ArrayBufferFile references can also be created using numerical file descriptors or file:// URLs.
JSTime.file(1234);JSTime.file(new URL(import.meta.url)); // reference to the current fileA BunFile can point to a location on disk where a file does not exist.
const notreal = JSTime.file("notreal.txt");notreal.size; // 0notreal.type; // "text/plain;charset=utf-8"The default MIME type is text/plain;charset=utf-8, but it can be overridden by passing a second argument to JSTime.file.
const notreal = JSTime.file("notreal.json", { type: "application/json" });notreal.type; // => "application/json;charset=utf-8"For convenience, JSTime exposes stdin, stdout and stderr as instances of BunFile.
JSTime.stdin; // readonlyJSTime.stdout;JSTime.stderr;Writing files (JSTime.write())
Section titled “Writing files (JSTime.write())”JSTime.write(destination, data): Promise<number>
The JSTime.write function is a multi-tool for writing payloads of all kinds to disk.
The first argument is the destination which can have any of the following types:
string: A path to a location on the file system. Use the"path"module to manipulate paths.URL: Afile://descriptor.BunFile: A file reference.
The second argument is the data to be written. It can be any of the following:
stringBlob(includingBunFile)ArrayBufferorSharedArrayBufferTypedArray(Uint8Array, et. al.)Response
All possible permutations are handled using the fastest available system calls on the current platform.
| Output | Input | System call | Platform | | --- | --- | --- | --- | | file | file | copy_file_range | Linux | | file | pipe | sendfile | Linux | | pipe | pipe | splice | Linux | | terminal | file | sendfile | Linux | | terminal | terminal | sendfile | Linux | | socket | file or pipe | sendfile (if http, not https) | Linux | | file (doesn’t exist) | file (path) | clonefile | macOS | | file (exists) | file | fcopyfile | macOS | | file | Blob or string | write | macOS | | file | Blob or string | write | Linux |
To write a string to disk:
const data = `It was the best of times, it was the worst of times.`;await JSTime.write("output.txt", data);To copy a file to another location on disk:
const input = JSTime.file("input.txt");const output = JSTime.file("output.txt"); // doesn't exist yet!await JSTime.write(output, input);To write a byte array to disk:
const encoder = new TextEncoder();const data = encoder.encode("datadatadata"); // Uint8Arrayawait JSTime.write("output.txt", data);To write a file to stdout:
const input = JSTime.file("input.txt");await JSTime.write(JSTime.stdout, input);To write an HTTP response to disk:
const response = await fetch("https://jstime.dev");await JSTime.write("index.html", response);Incremental writing with FileSink
Section titled “Incremental writing with FileSink”JSTime provides a native incremental file writing API called FileSink. To retrieve a FileSink instance from a BunFile:
const file = JSTime.file("output.txt");const writer = file.writer();To incrementally write to the file, call .write().
const file = JSTime.file("output.txt");const writer = file.writer();
writer.write("it was the best of times\n");writer.write("it was the worst of times\n");These chunks will be buffered internally. To flush the buffer to disk, use .flush(). This returns the number of flushed bytes.
writer.flush(); // write buffer to diskThe buffer will also auto-flush when the FileSink’s high water mark is reached; that is, when its internal buffer is full. This value can be configured.
const file = JSTime.file("output.txt");const writer = file.writer({ highWaterMark: 1024 * 1024 }); // 1MBTo flush the buffer and close the file:
writer.end();Note that, by default, the jstime process will stay alive until this FileSink is explicitly closed with .end(). To opt out of this behavior, you can “unref” the instance.
writer.unref();
// to "re-ref" it laterwriter.ref();Benchmarks
Section titled “Benchmarks”The following is a 3-line implementation of the Linux cat command.
// Usage// $ jstime ./cat.ts ./path-to-file
import { resolve } from "path";
const path = resolve(process.argv.at(-1));await JSTime.write(JSTime.stdout, JSTime.file(path));To run the file:
$ jstime ./cat.ts ./path-to-fileIt runs 2x faster than GNU cat for large files on Linux.

Reference
Section titled “Reference”interface JSTime { stdin: BunFile; stdout: BunFile; stderr: BunFile;
file(path: string | number | URL, options?: { type?: string }): BunFile;
write( destination: string | number | BunFile | URL, input: | string | Blob | ArrayBuffer | SharedArrayBuffer | TypedArray | Response, ): Promise<number>;}
interface BunFile { readonly size: number; readonly type: string;
text(): Promise<string>; stream(): Promise; arrayBuffer(): Promise; json(): Promise<any>; writer(params: { highWaterMark?: number }): FileSink;}
export interface FileSink { write( chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, ): number; flush(): number | Promise<number>; end(error?: Error): number | Promise<number>; start(options?: { highWaterMark?: number }): void; ref(): void; unref(): void;}