610

Is there a way to determine if you have packages in your package.json file that are no longer needed?

For instance, when trying out a package and later commenting or deleting code, but forgetting to uninstall it, I end up with a couple packages that could be deleted.

What would be an efficient way to determine if a package could safely be deleted?

Flip
  • 6,233
  • 7
  • 46
  • 75
Josh C
  • 7,461
  • 3
  • 24
  • 21

13 Answers13

761

You can use an npm module called depcheck (requires at least version 10 of Node).

  1. Install the module:

     npm install depcheck -g
    
     or
    
     yarn global add depcheck
    
  2. Run it and find the unused dependencies:

     depcheck
    

The good thing about this approach is that you don't have to remember the find or grep command.

To run without installing use npx:

npx depcheck 
Mostafiz Rahman
  • 8,169
  • 7
  • 57
  • 74
German Attanasio
  • 22,217
  • 7
  • 47
  • 63
  • 1
    `return new Promise(function (resolve, reject) {: ReferenceError: Promise is not defined` ... too bad. gonna go with npm-check – Boern Dec 16 '15 at 22:27
  • 11
    depcheck-es6 is now merged into depcheck – cyberwombat Jan 04 '16 at 00:27
  • 130
    doesnt look useful. I am using the standard angular2 cli setup and `depcheck` lists every package as `unused` which is just wrong – phil294 Feb 10 '17 at 19:07
  • 1
    I used this over npm-check because there's a module for gulp integration: https://github.com/depcheck/gulp-depcheck. – Westy92 Mar 20 '17 at 21:08
  • This package completely lagged down my Mac running High Sierra, I would not recommend using it. – lapint May 04 '18 at 15:22
  • 3
    It shows some dependencies as unused which are actually getting used such as babel-cli, css-loader, sass-loader and many more which are getting used in build process. – Sakshi Nagpal May 17 '18 at 06:54
  • 2
    For typescript, install using `npm install -g depcheck typescript`. However, even with this option, every dependency was listed as unused. – Doug Domeny Jun 20 '18 at 14:05
  • 14
    NB. depcheck doesn't take into account packages used in scripts specified in package.json – Javier Arias Oct 02 '18 at 15:02
  • 37
    To run it just once (w/o installation) - use [npx](https://www.npmjs.com/package/npx): `npx depcheck` – Kiril Nov 07 '18 at 17:59
  • 3
    I had a grunt build, and this suggested to remove all grunt packages under devDependencies. Not a good idea :) – swateek Dec 17 '18 at 13:06
  • There is an option to ignore certain packages like `eslint-*` or `gulp-`. – German Attanasio Dec 17 '18 at 14:17
  • 2
    so now who will remove this `depcheck`? – sanjeevprasad Feb 26 '19 at 12:24
  • 4
    Doesn't work. I just ran `depcheck` on my Gatsby project and it listed almost all of my packages as `unused` even though most of them are actually used. – Atte Juvonen Mar 14 '19 at 00:03
  • @AtteJuvonen there is a way to specify which pages should be skipped like `eslint` or `babel`. What are the packages that are being listed for you? – German Attanasio Mar 15 '19 at 11:26
  • 1
    It lists a lot of packages that are actually used, including `gatsby-plugin-google-analytics` and `typescript`. – Atte Juvonen Mar 15 '19 at 21:14
  • 27
    Didn't work for me. It listed all the packages as unused. – dev27 May 20 '19 at 22:20
  • Running on old angular project saying `No depcheck issue` which is wrong as there is definitely some unused packages I can tell – angularrocks.com Feb 03 '20 at 06:44
  • Yeah same as the rest, finding depcheck is pretty useless to be honest, lists many packages that are in use as unused. – el-davo Jun 09 '21 at 08:15
  • 2
    `depcheck` jacked up my dependencies pretty badly. I just blindly trusted it and removed the packages that it said were unused. My project still built, but there were unseen problems with removing the dependencies, and down the road, I had a lot of issues. – JCollier Oct 06 '21 at 15:38
  • depcheck didnt work for me. It listed some as unused, so I removed them. Then when I did a build, it failed to find the dependencies I just removed !! – daveD Feb 07 '22 at 15:56
  • `depcheck` doesn't seem to work for Vue3 single file components. If flags dependencies as unused that are clearly used in the app. Looking at the comments it doesn't seem to work with SPA frameworks in general. Does anyone know any such package that works with vue? – Fred Nov 12 '22 at 10:33
200

There is also a package called npm-check:

npm-check

Check for outdated, incorrect, and unused dependencies.

enter image description here

It is quite powerful and actively developed. One of it's features it checking for unused dependencies - for this part it uses the depcheck module mentioned in the other answer.

alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • 18
    Seems to give me the same results as depcheck. It looks like it even uses depcheck to find the unused dependencies. – Alex K Sep 14 '18 at 16:55
  • 6
    ```npm outdated```checks and lists current, wanted and latest package versions. No list of unused packages though. – mgarde Oct 25 '18 at 11:34
  • 6
    doesnt look useful as well. I am using the standard angular setup and this also lists every package as unused which is just as wrong – Kyle Burkett Jun 27 '19 at 17:00
  • 1
    Seems a bit outdated now. It includes high severity vulnerabilities right now... – jjmerelo Jul 22 '21 at 06:14
62

Check the unused dependencies

npm install depcheck -g
depcheck

enter image description here

Check the outdated library

npm outdated

enter image description here

Sathiamoorthy
  • 8,831
  • 9
  • 65
  • 77
  • 1
    `depcheck` doesn't seem to work for Vue3 single file components. If flags dependency as unused that is clearly used in the app. Do you know any such package that works with vue? – Fred Nov 12 '22 at 10:29
15

Many of the answer here are how to only find unused items. What if... I wanted to AUTOmatically -- a) find + b) Remove the unused items?

Option 2, below seems to be the newer way.


Option 1:

  1. Install this node project.
 $ npm install -g typescript tslint tslint-etc

  1. At the root dir, add a new file tslint-imports.json
{
  "extends": [
    "tslint-etc"
  ],
  "rules": {
    "no-unused-declaration": true
  }
}

  1. Run this at your own risk, make a backup :)
$ tslint --config tslint-imports.json --fix --project .

Option 2 (per @Alex & @JacopKane suggestions, thanks):

// newer one line option
npx depcheck --json | jq '.dependencies[]' | xargs -L1 npm rm

// or
npm uninstall $(npx depcheck --oneline)
bfontaine
  • 18,169
  • 13
  • 73
  • 107
Transformer
  • 6,963
  • 2
  • 26
  • 52
15

The script from gombosg is much better then npm-check.
I have modified a little bit, so devdependencies in node_modules will also be found.
example sass never used, but needed in sass-loader

#!/bin/bash
DIRNAME=${1:-.}
cd $DIRNAME

FILES=$(mktemp)
PACKAGES=$(mktemp)

# use fd
# https://github.com/sharkdp/fd

function check {
    cat package.json \
        | jq "{} + .$1 | keys" \
        | sed -n 's/.*"\(.*\)".*/\1/p' > $PACKAGES
    echo "--------------------------"
    echo "Checking $1..."
    fd '(js|ts|json)$' -t f > $FILES
    while read PACKAGE
    do
        if [ -d "node_modules/${PACKAGE}" ]; then
            fd  -t f '(js|ts|json)$' node_modules/${PACKAGE} >> $FILES
        fi
        RES=$(cat $FILES | xargs -I {} egrep -i "(import|require|loader|plugins|${PACKAGE}).*['\"](${PACKAGE}|.?\d+)[\"']" '{}' | wc -l)

        if [ $RES = 0 ]
        then
            echo -e "UNUSED\t\t $PACKAGE"
        else
            echo -e "USED ($RES)\t $PACKAGE"
        fi
    done < $PACKAGES
}

check "dependencies"
check "devDependencies"
check "peerDependencies"

Result with original script:

--------------------------
Checking dependencies...
UNUSED           jquery
--------------------------
Checking devDependencies...
UNUSED           @types/jquery
UNUSED           @types/jqueryui
USED (1)         autoprefixer
USED (1)         awesome-typescript-loader
USED (1)         cache-loader
USED (1)         css-loader
USED (1)         d3
USED (1)         mini-css-extract-plugin
USED (1)         postcss-loader
UNUSED           sass
USED (1)         sass-loader
USED (1)         terser-webpack-plugin
UNUSED           typescript
UNUSED           webpack
UNUSED           webpack-cli
USED (1)         webpack-fix-style-only-entries

and the modified:

Checking dependencies...
USED (5)         jquery
--------------------------
Checking devDependencies...
UNUSED           @types/jquery
UNUSED           @types/jqueryui
USED (1)         autoprefixer
USED (1)         awesome-typescript-loader
USED (1)         cache-loader
USED (1)         css-loader
USED (2)         d3
USED (1)         mini-css-extract-plugin
USED (1)         postcss-loader
USED (3)         sass
USED (1)         sass-loader
USED (1)         terser-webpack-plugin
USED (16)        typescript
USED (16)        webpack
USED (2)         webpack-cli
USED (2)         webpack-fix-style-only-entries
mMo
  • 233
  • 2
  • 10
  • 3
    Adding `-P 32` switch to your xargs will result in a huge speedup. – Justin Dehorty Aug 17 '21 at 20:54
  • Best solution compared to depcheck and derivatives. Adding `--max-procs|-P 32` greatly improves the speed. – Cameron Wilby Sep 02 '21 at 05:53
  • Great script that nicely extended the orginal one, but it got unusable slow (even xargs -P options) on a large react app. Re-organized file searches and shared a version that should produce same output, but not necessary in the same order. – Manwe Oct 25 '21 at 12:44
  • I had `import { Request, Response } from 'express';` in some files and in package.json I had `"@types/express": "^4.17.13"` This script reported `"@types/express": "^4.17.13"` as unused – ontherocks Jul 03 '23 at 15:16
  • Link to @Manwe's modified script for future readers: https://stackoverflow.com/a/69708249/3554391 – MHebes Aug 25 '23 at 19:24
12

fiskeben wrote:

The downside is that it's not fully automatic, i.e. it doesn't extract package names from package.json and check them. You need to do this for each package yourself.

Let's make Fiskeben's answer automated if for whatever reason depcheck is not working properly! (E.g. I tried it with Typescript and it gave unnecessary parsing errors)

For parsing package.json we can use the software jq. The below shell script requires a directory name where to start.

#!/bin/bash
DIRNAME=${1:-.}
cd $DIRNAME

FILES=$(mktemp)
PACKAGES=$(mktemp)

find . \
    -path ./node_modules -prune -or \
    -path ./build -prune -or \
    \( -name "*.ts" -or -name "*.js" -or -name "*.json" \) -print > $FILES

function check {
    cat package.json \
        | jq "{} + .$1 | keys" \
        | sed -n 's/.*"\(.*\)".*/\1/p' > $PACKAGES

    echo "--------------------------"
    echo "Checking $1..."
    while read PACKAGE
    do
        RES=$(cat $FILES | xargs -I {} egrep -i "(import|require).*['\"]$PACKAGE[\"']" '{}' | wc -l)
        if [ $RES = 0 ]
        then
            echo -e "UNUSED\t\t $PACKAGE"
        else
            echo -e "USED ($RES)\t $PACKAGE"
        fi
    done < $PACKAGES
}

check "dependencies"
check "devDependencies"
check "peerDependencies"

First it creates two temporary files where we can cache package names and files.

It starts with the find command. The first and second line make it ignore the node_modules and build folders (or whatever you want). The third line contains allowed extensions, you can add more here e.g. JSX or JSON files.

A function will read dependendy types.

First it cats the package.json. Then, jq gets the required dependency group. ({} + is there so that it won't throw an error if e.g. there are no peer dependencies in the file.)

After that, sed extracts the parts between the quotes, the package name. -n and .../p tells it to print the matching parts and nothing else from jq's JSON output. Then we read this list of package names into a while loop.

RES is the number of occurrences of the package name in quotes. Right now it's import/require ... 'package'/"package". It does the job for most cases.

Then we simply count the number of result lines then print the result.

Caveats:

  • Won't find files in different imports e.g. tsconfig.json files (lib option)
  • You have to grep manually for only ^USED and UNUSED files.
  • It's slow for large projects - shell scripts often don't scale well. But hopefully you won't be running this many times.
gombosg
  • 893
  • 10
  • 11
  • 1
    Editors sometimes cause imports to wrap into multiple lines. Would this script catch statements where ‘import’ or ‘require’ would be on a different line than the ‘from “PACKAGE_NAME”’? In other words, does it ignore whitespace in import or require statements? – vdiaz1130 Mar 11 '20 at 13:31
7

For checking unused dependencies, libraries and unimported files

 npx unimported 
Mujahidul Islam
  • 265
  • 4
  • 8
  • 2
    Unable to locate entry points for this node project. Please declare them in package.json or .unimportedrc.json – PirateApp Jun 10 '22 at 05:59
  • 1
    Worked for me, gives a lot of false-positives for 'unimported files' but the list of modules seemd fine. – sommmen Sep 14 '22 at 10:25
  • "Unable to locate entry points" error in Node 18. Is `"main": "./dist/index.js",` the issue here, since the `dist` folder isn't checked in? – jcollum Jul 25 '23 at 17:07
  • this will create false positives for dynamic imports e.g. in Next.js: const NoSSRForceGraph = dynamic(() => import("./NoSSRForceGraph"), { ssr: false, }); – Jon Willis Aug 21 '23 at 18:21
6

If you're using a Unix like OS (Linux, OSX, etc) then you can use a combination of find and egrep to search for require statements containing your package name:

find . -path ./node_modules -prune -o -name "*.js" -exec egrep -ni 'name-of-package' {} \;

If you search for the entire require('name-of-package') statement, remember to use the correct type of quotation marks:

find . -path ./node_modules -prune -o -name "*.js" -exec egrep -ni 'require("name-of-package")' {} \;

or

find . -path ./node_modules -prune -o -name "*.js" -exec egrep -ni "require('name-of-package')" {} \;

The downside is that it's not fully automatic, i.e. it doesn't extract package names from package.json and check them. You need to do this for each package yourself. Since package.json is just JSON this could be remedied by writing a small script that uses child_process.exec to run this command for each dependency. And make it a module. And add it to the NPM repo...

fiskeben
  • 3,395
  • 4
  • 31
  • 35
4

In Yarn 2.x and above, use:

yarn dlx depcheck

yarn dlx is designed to execute one off scripts that may have been installed as global packages with yarn 1.x. Managing system-wide packages is outside of the scope of yarn. To reflect this, yarn global has been removed.

Source: https://yarnpkg.com/getting-started/migration#use-yarn-dlx-instead-of-yarn-global

Sapnesh Naik
  • 11,011
  • 7
  • 63
  • 98
1

We can use the below npm module for this purpose:

https://www.npmjs.com/package/npm-check-unused

  • it revealed some not used ones but also used ones, still helpful I guess :-) It doesn't understand webpack loaders ;-) – OZZIE Sep 02 '19 at 13:07
1

Unless I've misunderstood something about the scripts by gombosg and nMo. Here's a faster version of nMo script-extensions with defaulting to 'find', but can be easily modified to use 'fd' for find functionality.

Changes are that it first finds all relevant files and then grep packages from all relevant files on one go and not a file-by-file bases.

Concurrency can be controlled and defaults to 8.

#!/bin/bash
DIRNAME=${1:-.}
cd "$DIRNAME"

FILES=$(mktemp)
PACKAGES=$(mktemp)

export NUMCONCURRENT=8

function findCmd {
  startPath=${1:-.}
  find "$startPath" \
    -path ./node_modules -prune -or \
    -path ./build -prune -or \
    \( -name "*.ts" -or -name "*.js" -or -name "*.json" \) -print
}

# use fd
# https://github.com/sharkdp/fd
function findCmd_fd {
  startPath=${1:-.}
  fd  -t f '(js|ts|json)$' "$startPath"
}



function check {
    cat package.json \
        | jq "{} + .$1 | keys" \
        | sed -n 's/.*"\(.*\)".*/\1/p' > "$PACKAGES"
    echo "--------------------------"
    echo "Checking $1..."

    findCmd > "$FILES"
    while read PACKAGE
    do
        #echo "node_modules/${PACKAGE}"
        if [ -d "node_modules/${PACKAGE}" ]; then
                findCmd node_modules/${PACKAGE} >> $FILES
        fi
    done < $PACKAGES
    export FILES
    export SQ="'"
    xargs -P ${NUMCONCURRENT:-1} -r -a  "$PACKAGES" -I[] bash -c '
        PACKAGE="[]"

        RES=$(cat "$FILES" | xargs -r egrep -i "(import|require|loader|plugins|${PACKAGE}).*[\"${SQ}](${PACKAGE}|.?\d+)[\"${SQ}]" | wc -l)

        if [ $RES = 0 ]
        then
            echo -e "UNUSED\t\t $PACKAGE"
        else
            echo -e "USED ($RES)\t $PACKAGE"
        fi
    '
    [ -f  "$PACKAGES" ] && rm "$PACKAGES"
    [ -f  "$FILES" ] && rm "$FILES"
}

check "dependencies"
check "devDependencies"
check "peerDependencies"

Manwe
  • 401
  • 2
  • 11
  • This worked like a charm, thank you! I tried the other scripts (by gombosg and nMo) and they gave me some used package as unused, by yours worked well. Cheers – Vivi Nov 18 '22 at 06:29
0

if you want to choose upon which giant's shoulders you will stand

here is a link to generate a short list of options available to npm; it filters on the keywords unused packages

https://www.npmjs.com/search?q=unused%20packages

Why is my answer just a link?

Typically I wouldn't provide just a link. This question deserves a less time-sensitive answer. The solution relies on up-to-date software. Recommending a specific piece of software that may have stopped being maintained (the case with some of the recommendations here) is of little use. Helping people find something current seems appropriate.

Kay V
  • 3,738
  • 2
  • 20
  • 20
0

I've created a package unused-package (https://www.npmjs.com/package/unused-package) which returns any unused packages or if package is devDependency but installed as normal dependecy

create a file and add this code to to your file

const check = require("unused-package");

check({ entries: ['entry path to your code'] }).then((res) => {
  console.log(res) // list of packages returned by library
});

one ADVANTAGE of usused-package over depcheck package is unused-package supports multiple entry path.

sai chand
  • 9
  • 2