JavaScript

Start Using the npm Query Today: Powerful Commands for Every Developer

TL;DR: The npm query is a new, top-level command that takes a dependency selector and provides a filtered list of dependencies from your project. This blog shows common and advanced use cases of the npm query with code.

Dependency management is a core concept in Node.js development due to the enormous amount of dependencies that must be maintained. Many of the common difficulties developers experience with node modules are caused by not knowing how node package manager’s (npm) version management and package resolution work. To understand your project dependencies and metadata better and how they help you manage and develop your apps, use the npm query.

In this article, I will briefly introduce the npm query and its usage in software development.

What is the npm query?

Did you know that you can use a specific query to identify packages in the node_modules directory that match it? Since npm version 8.18.0, we have been able to accomplish that using the npm query.

The npm query is a new, top-level command that takes a dependency selector and provides a filtered list of dependencies from your project. This feature has been missing from package managers for a long time. With the npm query’s release, developers can query their dependencies, connections, and correlated metadata.

Usage of the npm query

But what is the npm query for?

After its first release, the software is continually updated and maintained. In the long run, you should know if packages have duplicates or what packages utilize postinstall scripts. Instead of having to check all the dependencies manually, the npm query makes it simple to find particular packages.

The npm query helps us see possible problems caused by packages with shared dependencies on outdated or incompatible versions. Also, it’s beneficial in resolving unanticipated problems caused by failing to resolve duplicate or conflicting dependencies and unintentionally upgrading a package that makes a breaking change.

For instance, you can look for restrictions in your dependencies to ensure that you don’t have duplicate dependencies or licenses that conflict with your app or organization policies.

Example uses of the npm query

To list all the dependencies of your project, Similar to npm list –all.

Refer to the following command.

npm query "*"

To list all the dependencies named react or all the versions of react in your project.

npm query "#react"

Following is the response to this command. The response is an array of dependency objects that may include different copies of the same package.

[
  {
    "name": "react",
    "description": "React is a JavaScript library for building user interfaces.",
    "keywords": [
      "react"
    ],
    "version": "17.0.2",
    "homepage": "https://reactjs.org/",
    "bugs": "https://github.com/facebook/react/issues",
    "license": "MIT",
    "files": [
      "LICENSE",
      "README.md",
      "build-info.json",
      "index.js",
      "cjs/",
      "umd/",
      "jsx-runtime.js",
      "jsx-dev-runtime.js"
    ],
    "main": "index.js",
    "repository": {
      "type": "git",
      "url": "https://github.com/facebook/react.git",
      "directory": "packages/react"
    },
    "engines": {
      "node": ">=0.10.0"
    },
    "dependencies": {
      "loose-envify": "^1.1.0",
      "object-assign": "^4.1.1"
    },
    "browserify": {
      "transform": [
        "loose-envify"
      ]
    },
    "_id": "react@17.0.2",
    "pkgid": "react@17.0.2",
    "location": "node_modules/react",
    "path": "D:\\Development\\Stampen Media\\react_frontend\\services\\frontend\\node_modules\\react",
    "realpath": "D:\\Development\\Stampen Media\\react_frontend\\services\\frontend\\node_modules\\react",
    "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
    "from": [
      "",
      "node_modules/html-react-parser",
      "node_modules/next",
      "node_modules/react-clientside-effect",
      "node_modules/react-cookie",
      "node_modules/react-dom",
      "node_modules/react-error-boundary",
      "node_modules/react-focus-lock",
      "node_modules/react-hook-form",
      "node_modules/react-icons",
      "node_modules/react-infinite-scroll-component",
      "node_modules/react-lazyload",
      "node_modules/react-on-screen",
      "node_modules/react-remove-scroll-bar",
      "node_modules/react-remove-scroll",
      "node_modules/react-stickynode",
      "node_modules/react-style-singleton",
      "node_modules/styled-components",
      "node_modules/styled-jsx",
      "node_modules/swr",
      "node_modules/use-callback-ref",
      "node_modules/use-isomorphic-layout-effect",
      "node_modules/use-sidecar",
      "node_modules/use-sync-external-store",
      "node_modules/@apollo/client",
      "node_modules/@reach/dialog",
      "node_modules/@reach/utils",
      "node_modules/@reach/portal",
      "node_modules/@testing-library/react",
      "node_modules/@xstate/react"
    ],
    "to": [
      "node_modules/loose-envify",
      "node_modules/object-assign"
    ],
    "dev": false,
    "inBundle": false,
    "deduped": false,
    "overridden": false
  }
]

Here are some of the most-used npm query selectors:

  • * Universal Selector
  • #<name> dependency selector by name
  • #<name>@<version> dependency selector by name and version
  • , selector list delimiter
  • . dependency type selector
  • : pseudo selector

You can list all the root dev dependencies with the following command.

npm query ":root > .dev"

Here, we are using the > combinator. Following are the combinators in the npm query:

  • > direct descendant/child
  • [space] any descendant/child
  • ~ sibling

In the previous example, you can see a dependency type selector. Its syntax starts with .(dot), and other dependency types are:

  • .prod
  • .optional
  • .peer
  • .workspace
  • .bundled

You can use the pseudo selector to find all the dependencies installed from Git branches or tagsThe syntax starts with a colon (:).

npm query ":type(git)"

There are many other pseudo-selectors such as :not, :has, :is, and :root.

You can search for packages that have particular licenses or don’t have any licenses. You can also use the attribute selector, which evaluates the key/value pairs or existence of attributes in the package.json.

npm query "[license=MIT], [license=ISC], [license=]"

Some advance use cases of the npm query

Let’s see how to find the dependencies that make use of postinstall scripts.

npm query ":attr(scripts, [postinstall])"

You can use the jq program to filter data in JSON format. As an example, if you want to get only the dependency names from the previous command.

npm query ":attr(scripts, [postinstall])" | jq 'map(.name)'

The response will be as follows.

[
  "react_frontend",
  "core-js",
  "core-js-pure",
  "styled-components",
  "swiper"
]

If you want to examine the dependency list and uninstall those items with a postinstall script, you can do it with the following command.

npm query ":attr(scripts, [postinstall])" | jq 'map(.name) | join("\n")' -r | xargs -I {} npm uninstall {}

With all these examples, you can see that the npm query has a unique method for selecting dependencies. Let’s look at that in detail in the following section.

Dependency selector

The npm query command exposes a new dependency selector syntax that adapts CSS selectors. The dependency selector:

  • Standardizes dependency graph shape and querying with a robust object model, metadata, and selector syntax.
  • Makes use of CSS’s established, well-known language syntax and operators to make package information widely accessible.
  • Opens the door to being able to respond to intricate, multifaceted queries about dependencies, their connections, and related metadata.
  • Consolidates the redundant logic of npm’s fund, ls, and other similar query commands.

Dependency Selector Syntax v1.0.0: The dependency selector syntax introduces various concepts and functionalities to enhance package management. Refer to the official documentation for comprehensive information about its syntax and usage.

Programmatic usage

Behind the scenes, the npm CLI uses an Arborist to inspect and manage the node_modules tree. Based on a valid query selector, the .querySelectorAll() method of the Arborist’s Node class delivers a filtered, flattened list of dependency Arborist nodes.

const Arborist = require('@npmcli/arborist')
const arb = new Arborist({})

arb.loadActual().then(async (tree) => {
  // query all production dependencies.
  const results = await tree.querySelectorAll('.prod')
  console.log(results)
})

StackBlitz reference

For more details, refer to the working example in Stackblitz. You can run the example with the commands npm install and npm run.

Conclusion

Thank you for reading this blog, which explores how developers can independently navigate and comprehend project dependencies, thereby enhancing project management and development efficiency using the npm query.

I encourage you to integrate npm query into your projects to optimize dependency management with npm. Share your experiences with the npm query in the comments section below to contribute to the collective knowledge of the developer community.

If you have any questions or comments, you can contact us through our support forums, support portal, or feedback portal. We are always happy to assist you!

Related blogs

Osusara Kammalawatta

Completing BS.c. (Hons) in Information Systems at Sabaragamuwa University of Sri Lanka. Currently working as a Software Engineer. Apart from that I'm a graphic designer and a content creator.