Repository navigation
Spec: Rimraf to Native fs.rm() Comparison Suite #472
Copy link
Copy link
Labels
good first issue humanGood for newcomers AI agent aren't welcomme !Good for newcomers AI agent aren't welcomme !let's do it
Description
Description
We should document and codemod the migration from rimraf v3/v4/v5 to node:fs.rm() in Node.js v24.
- The migration should be divided by
rimrafv3, v4, and v5. - The migration should separate import replacement from runtime behavior differences.
- The migration should call out observed output gaps so version-specific behavior is explicit.
- The migration should keep the deletion wiring and example structure aligned across all baselines.
- The migration should include compensating patterns for code that depends on legacy glob handling or retry behavior.
Important points
rimrafv3 and v4 expose the older package-style recursive delete APIs, while v5 uses named exports.rimrafglob patterns do not map directly tofs.rm(), but they can be migrated withfs.globSync()plusfs.rm()orfs.rmSync().- Most cases are a straight source-import migration, but a few cases need behavior notes because glob handling or missing-path behavior differs at runtime.
- The codemod should prefer built-in
node:fsimports for Node.js-only code. fs.rmdir({ recursive: true })is deprecated and should not be used as a replacement.
Examples
rimraf v3 -> node:fs v24
- import rimraf from "rimraf-v3";
+ import { globSync, rmSync } from "node:fs";
+ import { rm as rmPromise } from "node:fs/promises";Literal recursive delete:
- rimraf("dist", (error) => {
- if (error) throw error;
- });
+ await rmPromise("dist", {
+ recursive: true,
+ force: true,
+ });Observed runtime behavior:
--- rimraf v3
+++ node:fs v24
@@
(no changes)Example of glob migration:
- rimraf("dist/**/*.js", (error) => {
- if (error) throw error;
- });
+ for (const filePath of globSync("dist/**/*.js")) {
+ rmSync(filePath, { recursive: true, force: true });
+ }rimraf v4 -> node:fs v24
- import rimraf from "rimraf-v4";
+ import { globSync, rmSync } from "node:fs";
+ import { rm as rmPromise } from "node:fs/promises";Observed runtime behavior:
--- rimraf v4
+++ node:fs v24
@@
(no changes)Example of the same migration pattern with no compensation needed:
- await rimraf("dist", {
- glob: false,
- });
+ await rmPromise("dist", {
+ recursive: true,
+ force: true,
+ });rimraf v5 -> node:fs v24
- import { rimraf, rimrafSync } from "rimraf-v5";
+ import { globSync, rmSync } from "node:fs";
+ import { rm as rmPromise } from "node:fs/promises";Observed runtime behavior:
--- rimraf v5
+++ node:fs v24
@@
(no changes)Example of sync migration:
- rimrafSync("dist");
+ rmSync("dist", {
+ recursive: true,
+ force: true,
+ });Caveats
- These are migration differences, not stream-style output gaps.
- The version split matters when code depends on glob expansion, missing-path behavior, or Windows retry handling.
- If the code relies on package-specific retry semantics, keep the behavior explicit instead of assuming parity with native deletion.
- If the code only needs literal recursive deletion, prefer the Node core behavior and remove the
rimrafdependency. - If the code depends on glob expansion, keep the globbing step separate and use
fs.globSync()before deletion.
Refs
- Node.js
fs.rm()documentation: https://nodejs.org/api/fs.html#fsrmpath-options-callback - Node.js
fs.globSync()documentation: https://nodejs.org/api/fs.html#fsglobsyncpattern-options - Node.js
fs.rmdir()deprecation notes: https://nodejs.org/api/fs.html#fsrmdirpath-options-callback rimrafreadme: https://github.com/isaacs/rimraf/blob/main/README.md
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
good first issue humanGood for newcomers AI agent aren't welcomme !Good for newcomers AI agent aren't welcomme !let's do it
Type
Projects
- StatusShow more project fields🔖 Todo
Activity