I need to find a way to get information about npm packages that are already installed. Specifically, I want to know where a module is located on disk and what command line tools it provides.
For instance, when I use a module like ‘express’ in my code, I can’t figure out how to get its installation folder or see what executable files it might have.
I’m looking for something that combines require functionality with package.json reading capabilities. Here’s what I’d like to achieve:
var packageInfo = require('package-details')
// retrieve module information
var moduleData = packageInfo.getInfo('express')
moduleData.version => '4.18.2'
moduleData.location => '/home/user/project/node_modules/express'
moduleData.executables => { express: '/home/user/project/node_modules/express/bin/express'}
// general information
packageInfo.globalBinPath => '/home/user/.npm/bin'
I tried using require.resolve and checking different paths, but the module locations don’t match what I see in require.paths. Even though require can find these modules, I can’t determine their actual location.
// In Node.js REPL
console.log(require.resolve.paths('express'))
// Shows paths like:
// ['/home/user/project/node_modules', '/home/user/node_modules', '/home/node_modules']
// But when I check:
const fs = require('fs')
fs.readdirSync('./node_modules/')
// Shows: ['express', 'lodash', 'moment', ...]
Any suggestions on how to get this package information programmatically?
I’ve hit this same issue across multiple projects. Here’s what works: use require.resolve() to find the main entry point, then walk up directories until you find package.json. But there’s actually a cleaner way using Node’s built-in modules. Combine require.resolve.paths() with fs.existsSync() to systematically check each possible location. Once you locate the right node_modules directory, build the path to your package folder and read package.json directly. For finding executables, parse the “bin” field from package.json. It’s either a string (one executable) or an object (multiple). Make sure you handle scoped packages by including the scope in your path resolution. One thing that tripped me up: some packages put their main file in subdirectories. Always traverse upward from the resolved path until you find a directory with package.json. This method’s been solid across different Node versions and package setups.
Combine require.resolve() with fs operations and package.json parsing. Use require.resolve() to get the exact file path, then navigate up to find the package root and read its metadata. Here’s a function that does this:
const path = require('path')
const fs = require('fs')
function getPackageInfo(moduleName) {
try {
const mainFile = require.resolve(moduleName)
let packageRoot = path.dirname(mainFile)
while (packageRoot !== path.dirname(packageRoot)) {
if (fs.existsSync(path.join(packageRoot, 'package.json'))) {
break
}
packageRoot = path.dirname(packageRoot)
}
const packageJson = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'))
const executables = {}
if (packageJson.bin) {
for (const [name, binPath] of Object.entries(packageJson.bin)) {
executables[name] = path.resolve(packageRoot, binPath)
}
}
return {
version: packageJson.version,
location: packageRoot,
executables: executables
}
} catch (error) {
throw new Error(`Package ${moduleName} not found`)
}
}
This works reliably since require.resolve() gives you the actual resolved path that Node.js uses internally.