sponsor β discord β npm β github
@reliverse/relifso is a modern node and bun filesystem toolkit. drop-in replacement for
node:fs
andfs-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-catch
for 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/relifso
Migrate:
bun rm fs-extra
bun rm @types/fs-extra
# soon:
# bun add -D @reliverse/dler
# bun dler migrate fs-relifso
Pro 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/catch
for 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-runtime
You 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
Promise
pattern 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-extra
tests 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)