redis/dead-dependencies
>- Find and safely remove unused ("dead") npm dependencies in RedisInsight using a grep + leaf-check + build-gate recipe. Use when cleaning up dependencies, investigating whether a package is still used, removing a suspected leftover, or when the user mentions dead deps, unused dependencies, dependency cleanup, leftover packages, or "is this safe to remove". Complements the weekly vulnerability audit (`scripts/dependency-audit-report.mjs`), which only reports vulnerabilities.
npx skills add https://github.com/redis/RedisInsight --skill dead-dependencies
Identify and safely remove unused npm dependencies. This is a **local,
interactive** workflow — a scheduled report can only ever guess; confirming a
dependency is dead requires grepping real usage and running the build.
Static tools over-report badly in this repo and must not be trusted blindly:
package.json is a mega-manifest (UI + desktop + build + test+ storybook + electron), so a tool scanning one area flags everything used
elsewhere as "unused".
import: webpack loadersand eslint/jest/babel plugins by string in config, tools invoked from
package.json scripts, runtime -r preloads, dynamic require, and
ambient @types/*.
mixed in with false positives.
The reliable signal is: **grep for usage → confirm it's a leaf → remove it and
run the build gate.** That is exactly how jsonpath was confirmed dead and
removed (worked example at the bottom).
PKG=jsonpath # the dependency to check
grep -rn "$PKG" \
redisinsight configs scripts tests .storybook \
--include=*.ts --include=*.tsx --include=*.js --include=*.jsx \
--include=*.mjs --include=*.cjs --include=*.json \
2>/dev/null | grep -v node_modules
Look for import ... from '$PKG', require('$PKG'), import('$PKG'), and
bare references. Ignore unrelated substring hits (e.g. nestjs-form-data when
checking form-data, or a package name appearing only in tutorial/manifest
text). Zero real references → candidate for the next steps.
A clean grep is necessary but not sufficient. Check the ways a package is
used without an import:
name: .eslintrc.js, configs/webpack.config.*.ts,
redisinsight/ui/vite.config.mjs, jest.config.cjs, babel.config.cjs,
electron-builder.json, .mocharc*. eslint plugins, webpack loaders, and
jest/mocha reporters live here.
package.json scripts — a tool like concurrently, lint-staged, or areporter is "used" if a scripts entry (any workspace) invokes it.
node -r <pkg>, require(variable), or awasm/worker loader with a computed path.
npm ls "$PKG" # in the workspace that declares it
Confirm nothing else in the tree depends on it, and note any transitive deps it
uniquely pulls (removing jsonpath also dropped underscore).
| Situation | Action |
| --- | --- |
| Plain runtime/dev dep, zero references anywhere | Delete (after the gate below) |
| @types/x where base x bundles its own types (node_modules/x/package.json has types/typings) | Delete — the DefinitelyTyped package is obsolete |
| @types/x that's ambient/global-only (e.g. @types/webpack-env) | Keep — never imported by design |
| Declared in more than one workspace (package.json), used in only one | Relocate/dedupe — remove the *unused* declaration, never the used copy |
| Shadows a Node builtin (buffer, assert, …) | Keep — usually a false positive |
| Referenced only in a config/scripts (step 2 hit) | Keep |
Remove it, reinstall (per the repo's dependency rules — never hand-edit
package.json/lockfile, never --ignore-scripts), and verify the affected
area builds:
npm uninstall "$PKG" # in the declaring workspace; updates the lockfile
npm run type-check # or the affected workspace's type-check
npm run test # / test:api, as relevant
npm run build # if it's a build-time dep
Green across the relevant checks = safe. Commit the package.json +
package-lock.json change (see the git-safety / dependency rules in
CLAUDE.md). If anything goes red, it wasn't dead — restore it.
To triage the whole surface rather than one package, list declared deps and
grep each for an import, then apply steps 2–5 to the ones with zero hits:
node -e "const p=require('./package.json');console.log([...Object.keys(p.dependencies||{}),...Object.keys(p.devDependencies||{})].join('\n'))" \
| while read PKG; do
hits=$(grep -rl --include=*.ts --include=*.tsx --include=*.js --include=*.jsx --include=*.mjs \
-e "from ['\"]$PKG" -e "require(['\"]$PKG" redisinsight configs scripts tests 2>/dev/null | grep -vc node_modules)
[ "$hits" = "0" ] && echo "candidate: $PKG"
done
This is a first filter only — every candidate still goes through steps 2–5.
Expect false positives (config/string/dynamic/ambient use). Never delete straight
from this list.
jsonpathmanifest.json; no import/require.
npm ls jsonpath → a leaf; it was also the sole reason underscore wasinstalled.
jsonpath + @types/jsonpath, npm install, npm run type-check→ green. Confirmed dead; committed. (underscore dropped with it.)
Take redis/dead-dependencies from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference npm.
Without those the skill loads but fails at the first command.