Delete files and directories
The del package is a robust utility for deleting files and directories in Node.js using glob patterns. It provides a Promise-based API that makes it safer and more flexible than Node's native fs.rm() or older tools like rimraf. With over 13 million weekly downloads, it's become the standard choice for build tools, test cleanup, and CI/CD pipelines that need pattern-based file deletion.
Originally created to solve the problem of reliably cleaning build artifacts across different operating systems, del handles edge cases that trip up naive deletion code: symlinks on Windows, permission errors, files in use, and deeply nested directory structures. It wraps these complexities behind a simple API that accepts glob patterns like dist/**/*.js or ['temp/*', '!temp/keep.txt'] with negation support.
The package is maintained by Sindre Sorhus and has evolved through eight major versions, progressively improving performance and adopting modern JavaScript features. Version 8.x requires Node 18+ and includes optimizations like configurable concurrency for parallel deletions, making it suitable for projects with thousands of generated files.
Developers typically use del in build scripts (webpack, Rollup, Vite plugins), test teardown hooks (Jest afterAll), or custom CLI tools where controlled file deletion is critical. Its dry-run mode lets you verify what would be deleted before committing to destructive operations, and the force option bypasses file-in-use restrictions when needed.
import del from 'del';
import path from 'path';
// Clean build artifacts before compilation
async function cleanBuild() {
const deleted = await del([
'dist/**',
'build/**/*.js',
'!build/vendor/**', // Keep third-party libs
'temp/*.log'
], {
dryRun: false,
concurrency: 50
});
console.log(`Deleted ${deleted.length} files`);
deleted.slice(0, 5).forEach(file =>
console.log(` - ${path.relative(process.cwd(), file)}`)
);
}
// Safe deletion with verification
async function safeClean(patterns) {
// Preview what would be deleted
const toDelete = await del(patterns, { dryRun: true });
if (toDelete.length === 0) {
console.log('No files to delete');
return;
}
console.log(`Will delete ${toDelete.length} items. Continue? (y/n)`);
// In real code, await user input here
const deleted = await del(patterns);
return deleted;
}
// Usage in test teardown
afterAll(async () => {
await del(['test-output/**', '.cache/test-*'], { force: true });
});
cleanBuild().catch(console.error);Build artifact cleanup: Before running a fresh build, clear previous output directories with patterns like await del(['dist/**', 'build/**']) to ensure no stale files remain, common in webpack/Rollup workflows where incremental builds can leave orphaned files.
Test environment reset: In integration tests, clean temporary files after each suite with afterAll(() => del('test-fixtures/tmp/**')) to prevent test pollution, particularly useful when tests generate SQLite databases or mock file uploads.
Log rotation scripts: Periodically delete old log files matching patterns like del(['logs/*.log', '!logs/current.log'], {force: true}) while preserving active logs, useful in long-running services without dedicated log management.
Cache invalidation: Clear specific cached assets with await del('cache/**/*.{jpg,png}', {concurrency: 100}) when rebuilding image assets, where high concurrency speeds up deletion of thousands of small files.
Monorepo maintenance: Clean all node_modules and dist folders across packages with del(['packages/*/node_modules', 'packages/*/dist']) before fresh installs, avoiding manual navigation through nested directories.
npm install delpnpm add delbun add del