{"id":29332993,"url":"https://github.com/duniul/clean-modules","last_synced_at":"2025-07-08T02:03:19.160Z","repository":{"id":41441251,"uuid":"317545645","full_name":"duniul/clean-modules","owner":"duniul","description":"🧹 Clean up/prune unnecessary files and reduce the size of your node_modules directory.","archived":false,"fork":false,"pushed_at":"2024-10-01T14:45:36.000Z","size":3908,"stargazers_count":122,"open_issues_count":1,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-07T07:05:00.578Z","etag":null,"topics":["ci","cli-tool","node","node-modules","npm","yarn"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/duniul.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-01T13:13:00.000Z","updated_at":"2025-07-01T05:40:34.000Z","dependencies_parsed_at":"2023-01-19T23:33:33.835Z","dependency_job_id":"ed0b5b35-29f8-4f33-af8c-41ccb3fc1392","html_url":"https://github.com/duniul/clean-modules","commit_stats":{"total_commits":127,"total_committers":8,"mean_commits":15.875,"dds":"0.25196850393700787","last_synced_commit":"cb2bb80e188510db7b06d880137ecce346ecf889"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/duniul/clean-modules","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duniul%2Fclean-modules","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duniul%2Fclean-modules/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duniul%2Fclean-modules/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duniul%2Fclean-modules/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/duniul","download_url":"https://codeload.github.com/duniul/clean-modules/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duniul%2Fclean-modules/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264149653,"owners_count":23564501,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ci","cli-tool","node","node-modules","npm","yarn"],"created_at":"2025-07-08T02:01:32.390Z","updated_at":"2025-07-08T02:03:19.140Z","avatar_url":"https://github.com/duniul.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# clean-modules 🧹\n\n\u003ca href=\"https://www.npmjs.com/package/clean-modules\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/clean-modules\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://www.npmjs.com/package/clean-modules\"\u003e\u003cimg src=\"https://img.shields.io/node/v-lts/clean-modules\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://www.npmjs.com/package/clean-modules\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/clean-modules?color=blue\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://bundlephobia.com/result?p=clean-modules\"\u003e\u003cimg src=\"https://img.shields.io/bundlephobia/min/clean-modules?color=brightgreen\" /\u003e\u003c/a\u003e\n\n\u003e Clean up/prune unnecessary files and reduce the size of your `node_modules` directory. Useful for\n\u003e CI caches or for reducing the size of serverless functions.\n\n- 🧹 Removes directories and files that are unnecessary and **safe to remove in production**\n- 🛠 Easily customizable through glob patterns (either through [CLI args](#positionals) or a\n  [configuration file](#glob-patterns-and-configuration-file))\n- 📁 Cleans up empty directories after removing files\n- ⚡️ Super fast, but still written in Node\n- 🔍 Allows analyzing results, like which pattern excluded which file\n- 🧑‍💻 Supports both CLI and programmatic usage\n\n\u003cp align=\"center\"\u003e\n  \u003cimg alt=\"Small project\" title=\"Small project\" src=\"images/small-project.png\" width=\"240\" /\u003e\n  \u003cimg alt=\"Large project\" title=\"Large project\" src=\"images/large-project.png\" width=\"240\" /\u003e\n  \u003cimg alt=\"Dry run\" title=\"Dry run\" src=\"images/dry-run.png\" width=\"240\" /\u003e\n\u003c/p\u003e\n\n## Table of contents\n\n\u003cdetails\u003e\u003csummary\u003eClick to open\u003c/summary\u003e\n\n- [Quick start](#quick-start)\n- [Installation](#installation)\n- [Commands](#commands)\n  - [`clean-modules clean` (default command) 🧹](#clean-modules-clean-default-command-)\n    - [Usage](#usage)\n    - [Positionals](#positionals)\n    - [Options](#options)\n      - [`--directory | -D`](#--directory---d)\n      - [`--glob-file | -f`](#--glob-file---f)\n      - [`--no-defaults | -n`](#--no-defaults---n)\n      - [`--keep-empty | -k`](#--keep-empty---k)\n      - [`--dry-run | -d`](#--dry-run---d)\n      - [`--json | -j`](#--json---j)\n      - [`--yes | -y`](#--yes---y)\n  - [`clean-modules analyze` 🔎](#clean-modules-analyze-)\n    - [Usage](#usage-1)\n    - [Positionals](#positionals-1)\n    - [Options](#options-1)\n    - [Example output](#example-output)\n- [Glob patterns and configuration file](#glob-patterns-and-configuration-file)\n  - [Example configuration file](#example-configuration-file)\n  - [Default globs](#default-globs)\n    - [Common extra inclusions](#common-extra-inclusions)\n    - [Common extra exclusions](#common-extra-exclusions)\n- [Programmatic usage](#programmatic-usage)\n- [Alternatives](#alternatives)\n  - [Comparisons](#comparisons)\n    - [clean-modules (this project)](#clean-modules-this-project)\n    - [yarn autoclean](#yarn-autoclean)\n    - [modclean](#modclean)\n    - [node-prune](#node-prune)\n    - [nm-prune](#nm-prune)\n\n\u003c/details\u003e\n\n## Quick start\n\nSimply run the command in the directory where your `node_modules` are:\n\n```bash\nclean-modules\n```\n\nYou can also pass any options that you need, like custom globs or a path to a specific\n`node_modules` directory.\n\n```bash\nclean-modules --directory \"path/to/node_modules\" \"extra/included/file/glob.txt\" \"!extra/excluded/glob.ts\n```\n\nCheck out the [command](#clean-modules-clean-default-command-🧹) section for all available options.\n\n## Installation\n\n`clean-modules` can be installed globally if you only want to use it as a CLI tool. You can also\ninstall it locally if you want to use it in a package command.\n\n```bash\n# global\nnpm install --global clean-modules\n\n# dev dependency\nnpm install --save-dev clean-modules\n```\n\n## Commands\n\n### `clean-modules clean` (default command) 🧹\n\nThe default command, cleans up your `node_modules` based on a set of _most likely_ safe glob\npatterns and removes empty directories.\n\n#### Usage\n\n```bash\nclean-modules [options] \u003c...globs\u003e\n```\n\n#### Positionals\n\nExtra glob patterns can be passed as positional arguments. By default they are combined with the globs loaded from the the default globs file and any custom globs file passed through the [`--glob-file`](#glob-file---f) option.\n\nFor information on how the globs are parsed, see the [Glob patterns](#glob-patterns-and-configuration-file) section.\n\n**Example**:\n\n```bash\n# include all TypeScript declaration files and @types folders\nclean-modules \"**/*.d.ts\" \"**/@types/**\"\n\n# exclude all sourcemap files and PNG files\nclean-modules \"!**/*.map.js\" \"!**/*.png\"\n\n# include .d.ts files but exclude PNG files\nclean-modules \"**/*.d.ts\" \"!**/*.png\"\n```\n\n#### Options\n\n##### `--directory | -D`\n\n`string` [default: `./node_modules`]\n\nAccepts a path to a directory to run the script on.\n\n**Example**:\n\n```bash\nclean-modules --directory \"path/to/custom/node_modules\"\n```\n\n##### `--glob-file | -f`\n\n`string` [default: `./.cleanmodules`]\n\nAccepts a path to a file from which clean-modules should read any custom globs. See the\n[glob patterns](#glob-patterns-and-configuration-file) section for information about how the glob\nfile works and what patterns work.\n\n##### `--no-defaults | -n`\n\n`boolean`\n\nExcludes all default globs, using only custom globs added through the\n[glob file](#glob-patterns-and-configuration-file) or by the include or exclude options. Useful if\nyou want complete control over what files to include.\n\nSee the [`.cleanmodules-default`](./cleanmodules-default) to see what patterns are included by\ndefault by default.\n\n##### `--keep-empty | -k`\n\n`boolean`\n\nSkips removing empty folders after removing files.\n\n##### `--dry-run | -d`\n\n`boolean`\n\nRuns the script and prints the result without actually removing any files. Does not count the number\nof removed empty directories.\n\n##### `--json | -j`\n\n`boolean`\n\nOnly logs a final JSON dump at the end of the script (useful for logs or services).\n\n##### `--yes | -y`\n\n`boolean`\n\nSkips the confirmation prompt at the start of the script.\n\n### `clean-modules analyze` 🔎\n\nCompiles a list of all files that would be included by `clean-modules` and gives a breakdown of:\n\n- exact file path\n- what glob patterns it was included by\n- how the patterns were formatted and passed along to `picomatch`\n- if the file was included by default\n\n#### Usage\n\n```bash\nclean-modules analyze [options]\n```\n\nBecause of the amount of data it can be useful to pipe it somewhere, like:\n\n```bash\nclean-modules analyze \u003e\u003e clean-modules-result.json\n```\n\n#### Positionals\n\nThe `analyze` command accepts the same type of positionals as the [default command]().\n\n#### Options\n\nThe `analyze` command accepts several of the default command's options and applies them in the same\nway:\n\n- [`--directory`](#directory---d)\n- [`--glob-file`](#glob-file---f)\n- [`--no-defaults`](#no-defaults---n)\n\n#### Example output\n\n```json\n[\n  {\n    \"filePath\": \"/Users/me/projects/foo/node_modules/dependency/__tests__/test1.js\",\n    \"includedByDefault\": true,\n    \"includedByGlobs\": [\n      {\n        \"original\": \"__tests__/\",\n        \"derived\": \"/Users/me/projects/foo/node_modules/dependency/**/__tests__/**\"\n      }\n    ]\n  }\n  // ...\n]\n```\n\n## Glob patterns and configuration file\n\nclean-modules accepts globs from either a configuration file (`.cleanmodules` next to\n`node_modules` by default) or CLI arguments. It uses\n[`.gitignore`-like](https://www.atlassian.com/git/tutorials/saving-changes/gitignore) glob patterns\nthat are converted to valid [`picomatch`](https://github.com/micromatch/picomatch) globs, which is\nwhat is used to match file paths under the hood.\n\n**Differences from regular gitignore syntax:**\n\n- To include a directory the pattern _must_ end with `/`, `/*` or `/**`\n  - This is to prevent directories matching common file names from being included by the globs.\n- Casing is ignored.\n\n**Like with .gitignore, globs should use forward-slashes as separators on all operative systems (including Windows)!**\n\n### Example configuration file\n\n```ignore\n# this is a comment (starts with a #)\n\n# to include include directories, end patterns with / or /* or /**\ndep1/\ndep1/*\ndep2/**\n\n# files are matched in any directory by default\n**/*.test.js\n# is the same as\n*.test.js\n\n# use a leading / to include a file or directory at a specific place\n/dep4/this/specific/directory/**\n/dep4/this/specific/file.js\n\n# to exclude a path, prepend it with a !\n!/not/this/directory/\n!not-me.js\n\n# to use leading exclamation marks without excluding, escape them\n\\!(*.d).ts\n```\n\n### Default globs\n\nThe default globs can be found in the [`.cleanmodules-default`](./.cleanmodules-default) file. It\nonly contains inclusions (as exclusions would override custom inclusions) and consists of a large\nlist of the most common files that are safe to remove.\n\nThat said, it's impossible to guarantee that none of the files are needed, and you might need to do\ncustom exclusions depending on what packages you use.\n\n#### Common extra inclusions\n\n- `**/*.d.ts`: **If you don't use TypeScript.** TypeScript declaration files take up a lot of space\n  in your `node_modules` folder, but they are most likely required to build your application. Useful\n  locally even if you don't use TypeScript since they can be parsed by your IDE.\n\n#### Common extra exclusions\n\n- `!**/*.map.js`: **If you are running `clean-modules` locally or need source files in production.**\n  `clean-modules` removes sourcemap files by default since they take up a lot of space and does not\n  break builds when removed. They can be nice to have though, especially while developing.\n\n## Programmatic usage\n\nClean modules can be used programmatically too!\n\nSimply import the corresponding function from the package:\n\n````ts\nimport { clean, analyze } from 'clean-modules';\n\n// analyze, all options are optional\nconst analyzeResult = await analyze({\n  directory: '/path/to/node_modules',\n  globFile: '/path/to/.cleanmodules',\n  globs: ['**/*.js'],\n  noDefaults: false,\n});\n\n// clean, all options are optional\nconst cleanResult = await clean({\n  directory: '/path/to/node_modules',\n  globFile: '/path/to/.cleanmodules',\n  globs: ['**/*.js'],\n  noDefaults: false,\n  keepEmpty: false,\n  dryRun: false,\n});\n````\n\n## Alternatives\n\nThe most common issues I found with available tools are:\n\n- They only allow inclusion/exclusion of file names, not file paths. This prevents you from e.g.\n  excluding subdirectories of a specific folder, like `@types/react-native`.\n- They include too many, or too few, patterns by default. Lots of them also include patterns like\n  `*.ts` by default, which breaks TypeScript declaration files on build.\n- They are too slow (only relevant when running on large projects)\n- They are abandoned or don't respond to issues.\n\n### Comparisons\n\n#### clean-modules (this project)\n\n- ✅ Inclusion/exclusion through file path globs\n- ✅ Fast\n- ✅ Safe list of files and folders included by default (for production use)\n- ✅ Cleans up empty directories\n\n#### [yarn autoclean](https://classic.yarnpkg.com/en/docs/cli/autoclean/)\n\n- ✅ Included with Yarn by default\n- ✅ Inclusion/exclusion through globs\n- ⛔️ Very slow compared to alternatives\n- ⛔️ Runs on every install, both locally and in CI\n- ⛔️ Small list of files included by default\n\n#### [modclean](https://github.com/ModClean/modclean)\n\n- ✅ Cleans up empty directories\n- ✅ Safe list of files and folders included by default\n- ⛔️ Slow, only slightly faster than `yarn clean`\n- ⛔️ Only allows inclusion/exclusion by file name globs, not file path\n- ⛔️ Complains about empty folders that doesn't exist\n- ⛔️ Abandoned\n\n#### [node-prune](https://github.com/tj/node-prune)\n\n- ✅ Fastest option available\n- ⛔️ Written in Go and might require separate binary download\n- ⛔️ Removes some dangerous files by default (like `.d.ts` files and `assets` folder)\n- ⛔️ Only allows inclusion/exclusion by file name globs, not file path\n- ⛔️ Globs are very limited since it uses Go's `filepath.Match`\n- ⛔️ Does not remove empty folders\n\n#### [nm-prune](https://github.com/tuananh/node-prune)\n\n- ✅ Fast\n- ⛔️ Removes some dangerous files by default (like `.d.ts` files and `assets` folder)\n- ⛔️ Only allows inclusion/exclusion by file name, not file paths or globs\n- ⛔️ Does not remove empty folders\n- ⛔️ Small list of files included by default\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fduniul%2Fclean-modules","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fduniul%2Fclean-modules","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fduniul%2Fclean-modules/lists"}