runtime:fs

Blob-based file I/O, modeled on the web Blob surface — lazy file handles and writes that accept any web body.

Capability: FileRead / FileWrite

Exposed as an ES module under the runtime: scheme. Status: Available.

Everything is async

Every operation returns a Promise — there are no synchronous variants. esrun is a driven runtime with no thread of its own, so file I/O never blocks the event loop. Use await (top-level await works). Paths are a string, a file: URL, or a file() handle, and every path is confined to the project root jail.

Import

JavaScript
import { file, write, readDir, stat, mkdir, remove, rename, copy, Glob } from "runtime:fs";

Functions

FunctionTypeDescriptionExample
file(path)(path: PathLike) => FsFileA lazy, Blob-like handle — nothing is read until a read method is called.const f = file("./config/app.json")
write(dest, input, options?)(dest, body, { append? }) => Promise<number>Writes any web body (string, Blob, ArrayBuffer, TypedArray, Response, ReadableStream, file()) to dest; resolves to bytes written.await write("/srv/app/out.bin", bytes, { append: true })
readDir(path)(path) => Promise<DirEntry[]>Directory entries: { name, isFile, isDir, isSymlink }.for (const e of await readDir("./src")) …
stat(path)(path) => Promise<Stat>{ size, isFile, isDir, isSymlink, mtimeMs } — follows symlinks.const { size } = await stat("C:\data\cache.bin")
exists(path)(path) => Promise<boolean>Whether the path exists (a missing path is false, not an error).if (await exists("./.cache")) { … }
mkdir(path, options?)(path, { recursive? }) => Promise<void>Creates a directory; recursive creates missing parents.await mkdir("./logs/2026", { recursive: true })
remove(path, options?)(path, { recursive? }) => Promise<void>Removes a file or (with recursive) a directory tree.await remove("./tmp", { recursive: true })
rename(from, to)(from, to) => Promise<void>Renames or moves an entry (both jailed).await rename("./draft.md", "./final.md")
copy(from, to)(from, to) => Promise<number>Copies a file, overwriting the destination; resolves to bytes copied. Needs both FileRead and FileWrite.await copy("./a.txt", "./b.txt")
realPath(path)(path) => Promise<string>Canonical location — symlinks followed, ./.. removed. Throws if missing or outside the jail.await realPath("./a/../b")
readLink(path)(path) => Promise<string>The stored symlink target, verbatim (may be relative or dangling).await readLink("./link")
truncate(path, len?)(path, len) => Promise<void>Sets the file's length exactly, zero-filling if it grows.await truncate("./log", 0)
chmod(path, mode)(path, mode) => Promise<void>Sets permission bits. Windows honours only the owner-write bit, as the read-only flag.await chmod("./key.pem", 0o600)
makeTempDir(opts?)({ dir?, prefix? }) => Promise<string>Creates a directory with an unpredictable name; returns its path.await makeTempDir({ prefix: "build-" })
makeTempFile(opts?)({ dir?, prefix? }) => Promise<string>Creates an empty file with an unpredictable name; returns its path.await makeTempFile({ prefix: "up-" })
new Glob(pattern)GlobGlob matcher/scanner. match(path) is pure; scan(cwd | options) is an async iterator over the jailed tree. Patterns: *, **, ?, [a-z], [!x], {a,b}, leading !.new Glob("**/*.ts").match("src/app.ts") // true

FsFile — the file(path) handle

MemberReturnsDescription
pathstringThe path this handle points at.
text()Promise<string>Read the whole file as UTF-8 text.
json()Promise<any>Read and JSON.parse the file.
bytes()Promise<Uint8Array>Read the whole file as bytes.
arrayBuffer()Promise<ArrayBuffer>Read the whole file as an ArrayBuffer.
stream()ReadableStreamA readable byte stream of the file.
exists()Promise<boolean>Whether the file exists.
stat()Promise<Stat>File metadata (follows symlinks).
write(data, options?)Promise<number>Write to this file; resolves to bytes written.
writable(options?)WritableStreamA sink for piped/incremental writes. First chunk truncates unless { append: true } is set, rest append.
delete()Promise<void>Delete this file.

Temporary entries

makeTempDir / makeTempFile default to the base directory, not the OS temp directory — that is outside the root jail. Pass dir to place them elsewhere inside it. Names are unpredictable, and nothing is cleaned up automatically.

JavaScript
const dir = await makeTempDir({ prefix: "build-" });
try {
  // …
} finally {
  await remove(dir, { recursive: true });
}

Errors

ErrorWhen
TypeErrorA path isn't a string, URL, or file() handle; a non-file: URL is passed; write() gets an unsupported input type; or chmod() gets a non-integer mode.
DOMExceptionname "NotAllowedError" — the FileRead or FileWrite capability is not granted.
ErrorA filesystem failure surfaced by the OS (not found, permission denied, etc.).
Last updated on
Edit this page