nodejs / nodejs/userland-migrations
Spec: Rimraf to Native `fs.rm()` Comparison Suite
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 85
- Forks
- 55
- Avg merge
- 3d 11h
- Merged PRs (30d)
- 9
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
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the linked Node.js fs.rm(), fs.globSync(), and fs.rmdir() documentation and the rimraf README. Compare the v3, v4, and v5 examples for imports, glob handling, missing paths, and retry behavior; done means the comparison suite, codemod guidance, and compensating patterns cover each stated baseline.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100