sindresorhus/trash: reversible file deletion for Node.js scripts
Move files and directories to the trash
At a glance
- What is it?
- A Node.js module that moves files and folders to the operating system trash instead of unlinking them. It is a small API with a large platform surface, and the Linux backend is the weak point.
- Who is it for?
- Adopt trash when a Node script or build tool needs to remove files that a person might want back, and when the target machines are macOS or Windows. Do not adopt it for Linux fleets that depend on the trash spec being followed precisely, because the README says that implementation is not very good and not maintained, and warns Linux support may eventually be removed.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 12 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What trash replaces, and why unlink is the wrong default
Node's fs.unlink removes a file. There is no undo. The same is true of del and rimraf, which the README names directly as the tools this package is positioned against: they permanently delete files, while trash only moves them to the trash, which the README calls much safer and reversible. That sentence is the whole pitch, and it is a fair one. A build script that cleans a dist directory, a CLI that rewrites generated assets, a migration job that removes stale uploads: each of these is a place where a wrong glob pattern turns into data loss if the only tool available is unlink.
The audience is therefore Node developers writing scripts and tools, not end users. The package is a library first. A separate project, trash-cli, provides the command line, and the README points at it rather than shipping a binary here. If you want a shell command, you install that other package; if you want to call this from code, you install this one.
Platform backends: macos-trash, the XDG spec, recycle-bin
trash does not implement a trash directory itself. It dispatches. According to the README, macOS uses macos-trash, Windows uses recycle-bin, and Linux follows the XDG trash specification. On WSL, files are moved to the Windows Recycle Bin. That delegation is visible in package.json as well, where the dependencies include xdg-trashdir, wsl-utils, powershell-utils and @stroncium/procfs alongside general utilities such as globby, p-map, move-file and is-path-inside.
This is the design decision that matters most. Moving a file to the trash is not the same as moving it into a folder named .trash. The README's own FAQ makes the argument against hand-rolling it with mv: the mv command is not cross-platform, you hit file conflicts, the user cannot easily restore the file, it does not work on an external drive, the trash directory location varies between Windows versions, Linux has a specification to follow, and on macOS you lose the Put back feature. Each of those is a separate failure mode that the per-platform backends absorb.
Supported versions are stated as macOS 10.12 and later, Linux, and Windows 8 and later. Node itself must be 20 or higher, per the engines field in package.json.
Installing trash and trashing your first glob
Install it as a normal dependency. The package is ESM only (the type field in package.json is module), so it is imported, not required.
npm install trashThe README's usage example passes an array of glob patterns. A pattern prefixed with ! excludes matches, so this call trashes every PNG in the working directory except rainbow.png. The function returns a Promise, so it is awaited.
import trash from 'trash';
await trash(['*.png', '!rainbow.png']);After that call, the matched files should be in the operating system's trash rather than gone. On macOS they should be restorable through Put back. The second argument is an options object with a single documented key, glob, which defaults to true. Setting glob to false disables pattern matching so the strings are treated as literal paths.
For a shell workflow, the README directs you to a different package, trash-cli, installed globally:
npm install --global trash-cliSilent globs and the Windows service account trap
Two behaviours deserve attention before you build on this.
The first is that non-existent files and glob patterns that match nothing are silently ignored. The README is explicit and then tells you what to do about it: if you need to know whether files were actually trashed, check for their existence beforehand. There is no return value describing what happened, and no error thrown for a pattern that matched zero files. That is a reasonable default for a cleanup script and a poor one for a verification step. Code that assumes success after awaiting trash will happily report success on an empty match.
The second is Windows service accounts. When the process runs as SYSTEM or another service account, files go to that account's recycle bin, for example C:\$Recycle.Bin\S-1-5-18\ for SYSTEM. Those files are invisible in a normal user's recycle bin and may accumulate over time. The README's own advice for this case is to consider direct file deletion instead. So on a Windows service, the safety property you installed the package for does not hold: the file is not deleted, but it is also not recoverable by the person who would look for it.
The Linux backend is the reason to think twice
The README's opening note is unusually blunt: the Linux implementation is not very good and not maintained, help is welcome, and if no one steps up to help maintain it, Linux support will eventually be removed. That is the maintainer's own assessment, and it should shape the decision more than any feature list.
Cross-platform behaviour is therefore uneven in a way the API hides. The same await trash(path) call resolves on all three platforms, but the README's confidence in the backends is not the same across them. If your deployment target is Linux, you are relying on the part of the project the maintainer has flagged as weakest and least maintained, and on a specification implementation that third-party code depends on being correct. If your target is macOS or Windows, the delegation goes to backends the README describes without that caveat.
There is also a maintenance signal in the release history: v10.0.1 in December 2025, v10.1.0 in January 2026, v10.1.1 in February 2026, and the last push to the repository was on 2026-09-18. The project is not archived. It is also not moving quickly, which fits a library whose surface is a single function and an options object.
trash versus del and rimraf: same call site, opposite outcome
The obvious alternative is del, which the README lists under Related and names in the opening comparison. The API shape is similar: pass globs, get a promise. The difference is what happens to the bytes. del deletes; trash relocates. rimraf is the same story for directory trees. If your script's purpose is to free disk space permanently, del or rimraf is the correct tool and trash is the wrong one, because the file still occupies space in the trash until something empties it. The README points at empty-trash as the companion package for that job.
The other alternative is the mv command or fs.rename, and the README's FAQ is essentially a list of reasons that approach fails. The distinction is not stylistic. A rename into a directory you chose yourself does not participate in the platform's trash index, so the desktop environment will not offer to restore the file, and on an external drive the same path may not be writable at all. trash exists to route through the platform's own mechanism, and that routing is the feature.
Licence, upgrade cost, and what a major version means here
The package is MIT licensed, per both package.json and the license file in the repository root. MIT imposes no obligation on how you use the module beyond keeping the copyright notice with redistributed copies. That is a permissive baseline and nothing in the README or package.json suggests a dual-licence or commercial tier. This is not legal advice; read the licence text if the distinction matters to your organisation.
Upgrade cost is bounded by the API. There is one exported function, one options key, and a TypeScript declaration file at index.d.ts. The types are tested with tsd, which is part of the test script alongside xo and node --test. The practical constraint on upgrading is the Node version floor: package.json requires Node 20 or higher, so a project on an older runtime cannot take a current release without also moving its runtime. The dependency list is long for a package this size, and each of those transitive packages carries its own release cadence into your lockfile.
Editorial conclusion
Adopt trash when a Node script or build tool needs to remove files that a person might want back, and when the target machines are macOS or Windows. Do not adopt it for Linux fleets that depend on the trash spec being followed precisely, because the README says that implementation is not very good and not maintained, and warns Linux support may eventually be removed. Before wiring it into a pipeline, verify two things on your own target platform: that a glob which matches nothing is acceptable to your logic, since the README says such patterns are silently ignored, and that the process does not run as the Windows SYSTEM account, where files land in that account's recycle bin rather than the user's.
Frequently asked questions
How do I install the trash npm package?
Run npm install trash in your project. The package is ESM only, so import it rather than requiring it, and it needs Node 20 or higher according to package.json. For a shell command, the README points to a separate package, trash-cli, installed with npm install --global trash-cli.
Does trash work on Linux?
It does, following the XDG trash specification, but the README states that the Linux implementation is not very good and not maintained, and that Linux support will eventually be removed if no one helps maintain it. Treat Linux as the weakest of the three backends.
What happens if a glob pattern matches no files?
Non-existent files and glob patterns that match nothing are silently ignored. The README advises checking for the files' existence beforehand if you need to know whether anything was actually trashed.
Is trash different from del or rimraf?
Yes. The README says del and rimraf permanently delete files, while trash only moves them to the trash, which it describes as much safer and reversible. If you need the space reclaimed immediately, trash is the wrong tool because the file still sits in the trash until it is emptied.
What happens when trash runs as the Windows SYSTEM account?
Files are moved to that account's recycle bin, for example C:\$Recycle.Bin\S-1-5-18\ for SYSTEM, and will not be visible in a normal user's recycle bin. The README notes they may accumulate over time and suggests direct file deletion for service contexts.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/sindresorhus-trash)