sponsor β discord β npm β github
@reliverse/relifso is a modern node and bun filesystem toolkit. drop-in replacement for
node:fsandfs-extraβ powered by native promises, built with es modules, and packed with dx-focused and bun-aware utilities.
- π₯ Both Node.js and Bun-specific filesystem features are exposed via
fs.* - πͺ Everything you love from
fs-extraβ now simpler, cleaner, and more beginner-friendly - βοΈ Drop-in replacement for
node:fsβ with nativePromise,async/await, and sync variants - π€ Forget about
try-catchfor common errors like "file not found" β relifso does it under the hood - π§― Gracefully handles errors like
EMFILE(reading or writing a lot of files at once) and other edge cases - π Consistent error-first behavior β even for legacy APIs like
fs.exists() - π¦ First-class ESM and full TypeScript support β no config hacks required
- π§Ό Zero bloat β small size, zero deps, modern code, no monkey-patching
- π― Supports all Node.js v16+ features β optimized for Node.js v22+
- π§ͺ Soon: Ready for upcoming Node.js v22+ experimental features
- βοΈ Bun v1.2+ ready β ships with Bun-aware enhancements out of the box
- π¦βπ₯ Finally! Your
fs.*usage is now can correctly read/write JSON/JSONC! - π§ Built-in JSON repair β automatically fixes common JSON formatting issues
# bun β’ pnpm β’ yarn β’ npm
bun add @reliverse/relifsoMigrate:
bun rm fs-extra
bun rm @types/fs-extra
# soon:
# bun add -D @reliverse/dler
# bun dler migrate fs-relifsoPro Tip: Use Ctrl+Shift+H to replace fs-extra with @reliverse/relifso in your project.
-
File Operations
- Read/write files with various encodings
- Copy/move files and directories
- Create/remove files and directories
- File existence checks
- File stats and metadata access
-
Directory Operations
- Create nested directories
- Empty directories
- Directory traversal with
dive - Directory existence checks
-
JSON Operations
- Read/write JSON files with validation
- JSON repair and validation utilities
- JSON streaming support
- JSONC (JSON with Comments) support
- Automatic JSON repair for common issues:
- Missing quotes around keys
- Missing escape characters
- Missing commas and closing brackets
- Truncated JSON
- Single quotes to double quotes conversion
- Special quote characters normalization
- Special whitespace normalization
- Python constants (None, True, False) conversion
- Trailing comma removal
- Comment stripping
- Code block stripping
- Array/object ellipsis removal
- JSONP notation removal
- MongoDB data type conversion
- String concatenation
- Newline-delimited JSON conversion
-
Bun Optimizations
- Automatic runtime detection
- Optimized file operations using Bun APIs
- Fast file stats and metadata access
- Graceful fallbacks to Node.js APIs
-
Utility Functions
- File type detection
- Hidden file attribute handling
- Directory emptiness checks
- File size and last modified time access
- Graceful handling of common filesystem errors
- Consistent error types and messages
- Automatic error recovery where possible
- Detailed error information for debugging
- Runtime detection errors
- File operation failures
- All Bun-specific operations include proper error handling
- Automatic fallback from Bun to Node.js APIs when needed
Check ./e-relifso.ts and ./e-pathkit.ts for a full examples. You can clone this repo and run via bun dev.
Relifso works just like fs-extra β every method is promise-first, ergonomic, and future-ready.
import { copy, pathExists, remove } from "@reliverse/relifso";
await copy("src/index.ts", "dist/index.ts");
if (await pathExists("dist/index.ts")) {
await remove("dist/index.ts");
}- β¨ Everything's bundled β modern, async, and type-safe.
- π§Ό No more boilerplate like
promisify(fs.removeSync)or usingmkdirp,ncp, orrimraf. - π± No more weird
try/catchfor common errors like "file not found." - βοΈ Just clean, predictable APIs built for 2025 and beyond.
import {
ensureDir,
outputJson,
readJson,
remove,
} from "@reliverse/relifso";
const path = "./.reliverse/config.json";
await ensureDir(".reliverse");
await outputJson(path, { hello: "world" });
const config = await readJson(path);
console.log(config); // { hello: 'world' }
await remove(".reliverse");Install this repository locally and run the example by using bun dev:
$ bun e-mod.ts
β Running examples with Bun...
Created directory ./tests-runtime
[env] writeJson was successfully executed in Bun (for JSON)
Wrote JSON tests-runtime\config.json
[env] readJson was successfully executed in Bun
Read JSON {"hello":"world","ts":"2025-06-02T19:01:53.291Z"}
[env] copy was successfully executed in Bun
Moved β Copied (with overwrite) tests-runtime\config.old.json β tests-runtime\config.copy.json
[env] readFile was successfully executed in Bun
Wrote & read text file Hello Relifso!
[env] writeFile was successfully executed in Bun
[env] writeFile was successfully executed in Bun
Ensured nested & output files
[env] writeJson was successfully executed in Bun (for JSON)
[env] readJson was successfully executed in Bun
writeJson / readJson round-trip {"foo":"bar"}
[env] writeJson was successfully executed in Bun (for JSONC)
Wrote JSONC tests-runtime\config.jsonc
[env] readJson was successfully executed in Bun
Read JSONC {
"name": "relifso",
"version": "1.0.0",
"features": [
"file operations",
"directory operations",
"JSONC support"
],
"settings": {
"debug": true,
"verbose": false
}
}
Emptied directory tests-runtime\empty-me
[env] writeFileSync was successfully executed in Bun
[env] writeJsonSync was successfully executed in Bun (for JSON)
Sync JSON round-trip {"sync":true}
[env] copySync was successfully executed in Bun
copySync β moveSync β removeSync chain complete
Directory structure via dive
β’ tests-runtime\config-sync.json
β’ tests-runtime\config.copy.json
β’ tests-runtime\config.jsonc
β’ tests-runtime\config.old.json
β’ tests-runtime\config2.json
β’ tests-runtime\hello.txt
β’ tests-runtime\nested\deep\file.txt
β’ tests-runtime\output-file.txt
Directory structure via diveSync
β’ tests-runtime\config-sync.json
β’ tests-runtime\config.copy.json
β’ tests-runtime\config.jsonc
β’ tests-runtime\config.old.json
β’ tests-runtime\config2.json
β’ tests-runtime\hello.txt
β’ tests-runtime\nested\deep\file.txt
β’ tests-runtime\output-file.txt
Removed directory ./tests-runtimeYou choose your flavor:
// Async/Await
await copy("a.txt", "b.txt");
// Sync
copySync("a.txt", "b.txt");
// Callback (legacy-style)
copy("a.txt", "b.txt", err => {
if (err) console.error(err);
});All async methods return a Promise if no callback is passed.
- Written in modern ESM
- Minimal dependencies
- Full TypeScript declarations
- Compatible with Node.js 16+, best with 22+
- Async methods are built from the sync versions β no wrappers, no bloat
- All async methods follow the
Promisepattern by default. - All sync methods are safe and throw errors when needed.
- access
- appendFile
- copy
- copyFile
- cp
- createReadStream
- createWriteStream
- ensureFile
- exists
- mkdir
- mkdirs
- move
- open
- outputFile
- outputJson
- read
- readdir
- readFile
- readJson
- readLines
- readText
- rename
- rm
- rmdir
- stat
- symlink
- truncate
- unlink
- watch
- watchFile
- write
- writeFile
- writeJson
- chmod
- chown
- close
- dive
- emptyDir
- ensureLink
- ensureSymlink
- fchmod
- fchown
- forEachChild
- fstat
- ftruncate
- futimes
- gracefulify
- isDirectory
- isSymlink
lchmod- lchown
link- lstat
- lutimes
- mapChildren
- mapStructure
- mapStructureOrdered
- mkdtemp
- openAsBlob
- opendir
- readv
- realpath
- remove
- resolve
- statfs
- unwatchFile
- utimes
- vacuum
- writev
- accessSync
- appendFileSync
- copyFileSync
- copySync
- cpSync
- existsSync
- mkdirSync
- mkdirsSync
- moveSync
- openSync
- outputFileSync
- outputJsonSync
- readdirSync
- readFileSync
- readJsonSync
- readTextSync
- renameSync
- rmSync
- rmdirSync
- statSync
- symlinkSync
- truncateSync
- unlinkSync
- writeFileSync
- writeJsonSync
- writeSync
- chmodSync
- chownSync
- closeSync
- diveSync
- emptyDirSync
- ensureFileSync
- ensureLinkSync
- ensureSymlinkSync
- fchmodSync
- fchownSync
- fdatasync
- fdatasyncSync
- forEachChildSync
- fstatSync
- fsync
- fsyncSync
- ftruncateSync
- futimesSync
- isDirectorySync
lchmodSync- lchownSync
- linkSync
- lstatSync
- lutimesSync
- mkdirsSync
- mkdtempSync
- opendirSync
- readLinesSync
- readlinkSync
- readSync
- readvSync
- realpathSync
- removeSync
- statfsSync
- utimesSync
- writevSync
Relifso provides first-class support for Bun with automatic fallbacks to Node.js APIs. Here's how it works:
Relifso includes built-in JSON repair capabilities powered by jsonrepair, providing robust handling of malformed JSON files. This integration is particularly useful when dealing with JSON files that may have formatting issues or come from various sources.
- Automatic Repair: Automatically fixes common JSON formatting issues without requiring manual intervention
- Streaming Support: Handles infinitely large JSON documents through streaming
- Error Recovery: Gracefully handles and repairs various JSON syntax errors
- Performance Optimized: Efficient processing with configurable buffer sizes
import { readJson, writeJson } from "@reliverse/relifso";
// Reading a malformed JSON file
const malformedJson = `{
name: 'John', // Missing quotes and using single quotes
age: 30,
active: True, // Python-style boolean
tags: ['dev', 'js', ...], // Trailing ellipsis
metadata: {
lastLogin: ISODate("2024-03-20T10:00:00Z") // MongoDB date
}
}`;
// The JSON will be automatically repaired when reading
const data = await readJson("config.json");
console.log(data);
// Output: Properly formatted JSON with all issues fixed
// Writing JSON with automatic repair
await writeJson("output.json", data, { repair: true });For large JSON files, you can use the streaming API:
import { createReadStream, createWriteStream } from "@reliverse/relifso";
const inputStream = createReadStream("./data/broken.json");
const outputStream = createWriteStream("./data/repaired.json");
// The repair happens automatically during the stream
await pipeline(inputStream, outputStream);When using JSON operations, you can configure the repair behavior:
import { readJson } from "@reliverse/relifso";
const options = {
repair: true, // Enable automatic repair
streaming: {
chunkSize: 65536, // Size of output chunks
bufferSize: 65536 // Size of repair buffer
}
};
const data = await readJson("large.json", options);import { isBun } from "@reliverse/relifso";
if (isBun) {
console.log("Running in Bun!");
} else {
console.log("Running in Node.js");
}When running in Bun, relifso automatically uses Bun's optimized file system APIs:
Bun.file()for file operations- Native file existence checks
- Optimized file size and type detection
- Fast last modified time access
All Bun-specific operations include automatic fallbacks to Node.js APIs:
import { getStats } from "@reliverse/relifso";
// In Bun: Uses Bun.file() for faster stats
// In Node.js: Falls back to fs.stat()
const stats = await getStats("file.txt");getFile(path)- Get a Bun file referenceexists(path)- Check file existence using Bun's APIsize(path)- Get file size using Bun's APItype(path)- Get file MIME type using Bun's APIlastModified(path)- Get file last modified timegetStats(path)- Get file stats with Bun optimizationgetStatsSync(path)- Synchronous version of getStats
...
- Create usage example in ./example/e-relifso.ts and ./example/e-pathkit.ts
- Ensure ./example/e-relifso.ts and ./example/e-pathkit.ts works 100% correctly
- Consider using @reliverse/repath instead of just
node:path. - Pass all
fs-extratests with Bun (+ fix & improve them). - In docs.reliverse.org implement feature and performance comparison table with
fs-extra.
Relifso wouldn't be so cool without these gems:
If @reliverse/relifso reduced the number of lines in your codebase:
- β Star it on GitHub
- π Sponsor @blefnk
- π§ Recommend it to your dev friends
MIT Β© 2025 Nazar Kornienko (blefnk)