Using npm's `ls` command for Fun and Insight
Tags: javascript, node, webdev, opensource
Published: 2019-03-21 15:36:49

---
title: Using npm's `ls` command for Fun and Insight
published: true
description: I've been playing around a bunch with `npm ls` recently. I wanted to share some of the neat uses I've discovered!
tags: javascript, node.js, webdev, open-source
cover_image: https://thepracticaldev.s3.amazonaws.com/i/nf5ojh5yobpi5a5xlb91.png
---

One of my biggest problems with JavaScript and Node.js dependency trees is that it's... never been super easy to understand what you've got and what you can do to remediate.

I've been exploring the `npm ls` API a bit more recently, and wanted to share some of the things I've found that I wish I'd known about over the last few years!

## An Introduction to `npm ls`

If you're not familiar with `npm ls`, it's a command available with the npm CLI that will list dependencies that have been installed to `node_modules`. Additionally, it will return a non-zero exit code if the dependency tree that's resolved in `node_modules` is not what _should_ be resolved from `package.json`.

Here's a quick example of `npm ls` from one of my projects, [good-first-issue](https://github.com/bnb/good-first-issue):

{% gist https://gist.github.com/bnb/723647ad0541b9d89b762faf2541893b %}

> This command's output is 1339 lines long. See the full output in gist form here (it is too big to feel good about embedding it in this post!): https://gist.github.com/bnb/043d9d88820e3a5f31f0411e6ead141a


By just running `npm install`, I'll get 1337 modules in total. Yes, that's the real number with the module's current `package.json` – I'm just as surprised as you!

If you scroll through that list, you'll see a bunch of lines with `deduped` at the end. This means that npm was able to resolve a version of that module that met the requirements of multiple dependencies that require it to be installed. With my first-ever `grep` command (`grep deduped npm-ls.txt -c`), I was able to find the total number of modules that were deduped:

![My terminal, showing the output of `grep deduped npm-ls.txt -c` which is 532 – indicating that 532 modules were successfully deduped](https://thepracticaldev.s3.amazonaws.com/i/3lw6li8h866y0ftrcnpz.png)

It turns out that of 1337 modules, 532 were successfully deduped. It's worth noting that every line with `deduped` is a module that didn't need to be installed because it was installed via another path that _isn't_ marked as `deduped`. Given this context, we know that there were 805 modules installed in total.

## Bare vs. `--production` vs. `--development`

Being able to understand our dependency tree better is awesome! That said, `npm ls` by itself will tell you the current state of the entire `node_modules` directory... if you care about what's going to production, it'd be nice to separate the dependencies that will be shipped to production from the devDependencies that are simply used to make your life as a developer easier.

From running `npm ls --production` on the same project, we get a... much smaller result:

{% gist https://gist.github.com/bnb/bd01b6c4965a019b6f3797ae37d7f57c %}

This time, `npm ls` shows that we have only 110 modules. If we check for `deduped` with a slightly modified `grep` command, we'll see that 21 dependencies were deduped. Before deduping, `npm ls --production` in good-first-issue has a 12x reduction of modules when compared to the bare version of `npm ls`; after deduping, `npm ls --production` in good-first issue has a 9x reduction of modules when compared to the bare version of `npm ls`.

Understanding the modules introduced into production is fantastic and super valuable. But, what if you also want to understand your development dependencies?

Luckily, `npm ls` also provides a `--development` flag that allows you to understand the dependencies that are only used in development. There are a few more advanced use cases for this, most of which are geared toward helping developers like you and I understand what's being used locally and how it could be optimized.

## Usage to find how a specific module is introduced into your project

One neat feature of `npm ls` is the ability to pass a package name as an argument to the command. For example, if I wanted to find all instances of `graceful-fs` in my dependency tree I can run `npm ls graceful-fs` which will spit out the following:

![Terminal output of `npm ls graceful-fs` in my good-first-issue project. The intent of showing this is to provide an example of what kind of output you can expect from the `npm ls <package>` command in a real-world project.](https://thepracticaldev.s3.amazonaws.com/i/bgws8aqqjivh08l5o896.png)

For me, this is a stand-out feature! I spend a lot of time exploring the security space within Node.js and the JavaScript module ecosystem. This particular feature is incredibly useful to me, as one of the most common ways that you'll introduce security vulnerabilities is through your dependency tree (rather than directly introducing them in `package.json`). Being able to surface all instances of a specific module you _know_ is vulnerable is extremely useful, and this command makes that super simple.

## Usage in CI/CD for JavaScript projects

In a [recent discussion](https://github.com/nodejs/package-maintenance/pull/146#issuecomment-459784136) in the Node.js Package Maintenance team, usage of `npm ls` in CI/CD environments was raised as a possible best practice to ensure that the dependency tree that's being resolved by npm is entirely valid and will be able to run.

I'd not thought about this before, but it's an astoundingly good safeguard. Since `npm ls` will exit with a non-zero exit code if the dependency tree is invalid, the command effectively becomes a zero-effort safeguard in your CI/CD to make sure your dependency tree is resolving exactly how it should. Additionally, this idea can be combined with `npm ls --production` for production builds!

## Fin

I've been exploring `npm ls` a bit over the past few days, so I wanted to share my knowledge with y'all. I'm totally sure there's still more utility I've not discovered in the command, and would absolutely love to hear about it if you've got any tips! Additionally, I'd love to know if you're going to start using `npm ls` more, and how you're planning on using it! 💖