Fs Browser Side is a TypeScript library that brings Node.js FileSystem (fs) capabilities into the client-side environment, built on top of the File System Access API. It provides a clean, promise-based interface for managing files and directories within the browser.
- Promise-first API — All methods return
Promiseby default, with optional error-first callbacks. - Stateless path resolution — No mutable internal state; concurrent operations are safe.
- Robust path handling — Proper normalization with
.,.., and//support. - Idiomatic errors —
FsErrorextendsErrorwith typed error codes. - AsyncGenerator for recursive reads —
readdirRecursiveyields entries lazily viafor await...of. - Two access modes — User-picked directory (
showDirectoryPicker) or OPFS (navigator.storage).
pnpm add fs-browser-sideimport { FsBrowserSide } from 'fs-browser-side';
const fs = new FsBrowserSide();
// Request access to a user-selected directory
if (await fs.getAccess()) {
// Create nested directories
await fs.mkdir('/project/src', { recursive: true });
// Write a text file
await fs.writeFileText('/project/src/index.ts', 'console.log("hello");');
// Read it back
const content = await fs.readFileText('/project/src/index.ts');
console.log(content); // 'console.log("hello");'
// List directory contents
const entries = await fs.readdir('/project/src');
console.log(entries);
// [{ name: 'index.ts', type: 'file', path: '/project/src/index.ts' }]
}const fs = new FsBrowserSide({ navigatorMode: true });
await fs.getAccess(); // No user prompt needed| Option | Type | Default | Description |
|---|---|---|---|
navigatorMode |
boolean |
false |
Use OPFS instead of showDirectoryPicker |
Request file system access. Returns true on success.
Read a file as an ArrayBuffer.
Read a file as a UTF-8 string.
Write binary data to a file. Creates the file and parent directories if needed.
| Option | Type | Default | Description |
|---|---|---|---|
append |
boolean |
false |
Append to existing content |
Write a string to a file. Same options as writeFile.
Check if a file or directory exists at the given path.
Create a directory.
| Option | Type | Default | Description |
|---|---|---|---|
recursive |
boolean |
false |
Create parent directories as needed |
Remove a directory. Fails if non-empty unless recursive is true.
| Option | Type | Default | Description |
|---|---|---|---|
recursive |
boolean |
false |
Remove contents recursively |
Remove a file or directory entry.
| Option | Type | Default | Description |
|---|---|---|---|
recursive |
boolean |
false |
Remove directory contents recursively |
Copy a file from src to dest.
Move/rename a file (copy + remove).
List entries in a directory. Each DirEntry has name, type ('file' | 'directory'), and path.
Recursively yield all entries under a directory:
for await (const entry of fs.readdirRecursive('/')) {
console.log(entry.type, entry.path);
}Every method also accepts an error-first callback as last argument:
fs.readFileText('/file.txt', (err, content) => {
if (err) {
console.error(err.code, err.path);
return;
}
console.log(content);
});All errors are instances of FsError with a typed code:
import { FsError } from 'fs-browser-side';
try {
await fs.readFile('/missing.txt');
} catch (err) {
if (err instanceof FsError) {
console.log(err.code); // 'NOT_FOUND'
console.log(err.path); // '/missing.txt'
}
}| Code | Description |
|---|---|
NO_ACCESS |
File system access not granted |
NOT_FOUND |
Path does not exist |
ALREADY_EXISTS |
Path already exists |
PERMISSION_DENIED |
Insufficient permissions |
INVALID_PATH |
Invalid path (e.g. resolves above root) |
NOT_A_DIRECTORY |
Expected a directory |
NOT_A_FILE |
Expected a file |
UNKNOWN |
Unexpected error |
import { PathUtils } from 'fs-browser-side';
PathUtils.normalize('//a/./b/../c'); // '/a/c'
PathUtils.dirname('/a/b/c'); // '/a/b'
PathUtils.basename('/a/b/c'); // 'c'
PathUtils.join('/a', 'b', '../c'); // '/a/c'
PathUtils.segments('/a/b/c'); // ['a', 'b', 'c']The library requires browser support for the File System Access API. OPFS mode (navigatorMode: true) has broader compatibility than showDirectoryPicker.
- Browser-Based IDE — Read and write project files directly. Demo Github
- Custom CMS — Manage content files without a server.
- Offline-first apps — Persistent storage via OPFS.
- Client-side scraping — Save processed data to local files.
- Photo/file organizer — Manage user files in the browser.
You are completely free to contribute to this project! It would be my pleasure to review and accept your Pull Requests or Issues to improve this package.
This project is licensed under the MIT License.