| name | socket-dep-replace |
|---|---|
| description | Replace a dependency with an alternative package, eliminate it via code rewrite, or use socket-optimize for optimized replacements. |
Replace a dependency with an alternative package, eliminate it via code rewrite, or use socket-optimize for optimized replacements. This skill targets ONE specific package at a time - building a full usage map, presenting replacement strategies, and executing the migration with build and test verification.
- The user wants to swap a dependency for a different package (e.g., migrating from
momenttodayjs) - The user wants to replace a flagged or unmaintained dependency
- The user wants to inline a trivial utility package (e.g.,
is-odd,left-pad) - The user wants to use
socket-optimizeto find optimized replacements - The user asks how to migrate away from a specific package
- Socket CLI - optional but recommended. Required for Strategy A (
socket-optimize). Install via/socket-setupif not available. - Build and test commands - the project should have a working build and test setup for verification.
If the user specifies a package name, use that. If they also specify a replacement, note it for Step 5.
If the user isn't sure which package to replace, help them pick one:
- Suggest running
/socket-scanfirst to identify flagged or low-score dependencies - Check for packages with known maintenance issues or security alerts
- Look for trivial utility packages that could be inlined
One package at a time. If the user wants to replace multiple packages, run this workflow once per package sequentially.
Identify which ecosystem the target package belongs to by checking manifest and lock files:
| Ecosystem | Manifest Files |
|---|---|
| npm | package.json + package-lock.json |
| pnpm | package.json + pnpm-lock.yaml |
| yarn | package.json + yarn.lock |
| PyPI | requirements.txt, pyproject.toml, setup.py, setup.cfg, Pipfile |
| Cargo | Cargo.toml |
| Bundler | Gemfile |
| Maven | pom.xml |
| NuGet | *.csproj, packages.config |
| Go | go.mod |
For npm, pnpm, and yarn: differentiate by which lock file is present (package-lock.json, pnpm-lock.yaml, or yarn.lock).
Search the entire codebase for every reference to the target package. Be thorough - check all of the following:
| Ecosystem | Patterns to Search |
|---|---|
| npm/pnpm/yarn | require('pkg'), require("pkg"), import ... from 'pkg', import ... from "pkg", import 'pkg', import "pkg", import('pkg'), import("pkg"). Also check for subpath imports like pkg/sub. |
| PyPI | import pkg, from pkg import .... Note: the package name on PyPI often differs from the import name (e.g. Pillow → PIL, beautifulsoup4 → bs4, python-dotenv → dotenv, scikit-learn → sklearn, PyYAML → yaml). Check both the package name and common import aliases. Tip: run pip show <package-name> - the output includes a Location field and the actual top-level package names are the directories at that location matching the package. Alternatively, check top_level.txt in the package's .dist-info directory. |
| Cargo | use crate_name::, extern crate crate_name, references in proc-macro attributes. Note: hyphens in crate names become underscores in Rust code (e.g. serde-json → serde_json). |
| Bundler | require 'gem_name', require "gem_name", autoload references. |
| Maven | import groupId.artifactId. or subpackage patterns in .java and .kt files. Match on the groupId prefix. |
| NuGet | using Namespace; and using static Namespace. in .cs files. Match on the package's root namespace. |
| Go | Import paths in .go files matching the module path from go.mod require entries. |
Some dependencies are used indirectly and will not appear in import statements. Check all of the following for the target package:
@types/*packages - corresponds to a base package (e.g.@types/nodesupports Node.js APIs); check if the base package is used- Babel/ESLint/Jest/Prettier plugins - referenced by short name in config files (e.g.
eslint-plugin-reactis listed asreactin.eslintrc); search config files for the short name - CLI tools in
scripts- packages that provide binaries referenced inpackage.jsonscripts(e.g.rimraf,concurrently,cross-env); check thescriptsblock - Peer dependencies - required by other installed packages; check if any installed package lists it as a peer dependency
- Build tools and bundler plugins -
webpack,vite,rollup,esbuild,parcel,turbopackand their plugins; check config files - PostCSS/Tailwind plugins - referenced in
postcss.config.*ortailwind.config.* - Python entry points and console scripts - packages providing CLI commands configured in
pyproject.tomlorsetup.cfg - Bundler groups - gems in
:developmentor:testgroups may only be used in specific contexts - Cargo build dependencies - crates in
[build-dependencies]are used bybuild.rs - Maven plugins -
<plugin>entries inpom.xmlare not imported in code
Search beyond just source code:
- Source files (
.ts,.js,.py,.rs,.go,.java,.cs,.rb, etc.) - Configuration files (
.eslintrc,babel.config.*,jest.config.*,webpack.config.*,vite.config.*, etc.) package.jsonscriptsblock- CI/CD configs (
.github/workflows/,.gitlab-ci.yml, etc.) - Shell scripts (
*.sh) - Dockerfiles
- Documentation that references the package as a runtime dependency
This is what distinguishes dep-replace from dep-cleanup. For each call site, record:
- The file path and line number
- The specific APIs used (named imports, method calls, constructor invocations)
- The usage pattern (e.g., "uses
mergefor deep object merging", "usesformatfor date formatting")
This usage map drives the migration - it tells you exactly what API surface needs to be replaced.
Usage map for 'lodash':
src/utils/helper.ts:14 — import { merge, cloneDeep } from 'lodash'
- merge (deep object merge, called with 2 args)
- cloneDeep (object cloning)
src/api/handler.ts:3 — import { get, set } from 'lodash'
- get (nested property access with dot-path)
- set (nested property assignment with dot-path)
src/components/Table.tsx:8 — import { sortBy, groupBy } from 'lodash'
- sortBy (array sorting by key)
- groupBy (array grouping by key)
Unique APIs used: merge, cloneDeep, get, set, sortBy, groupBy (6 total)
Present ALL findings to the user with the full usage map:
**{package-name}** — found {N} usages across {M} files
Usage map:
{file}:{line} — {import statement}
- {api} ({usage pattern})
...
Unique APIs used: {list} ({count} total)
If the package has zero usages, suggest using /socket-dep-cleanup instead (it's unused, not needing replacement).
Present three strategies in priority order. If the user already specified a replacement package, skip to Strategy B with that package pre-selected.
If the Socket CLI is installed:
- Run
socket-optimize <package>to get optimized replacement suggestions - Present the suggestions to the user with package names, descriptions, and Socket scores
- If the user picks one, proceed to Step 6 with that replacement
If the Socket CLI is not installed, mention that socket-optimize is available via /socket-setup and move to Strategy B.
- Research candidate replacement packages - use knowledge of the ecosystem to identify 2-4 alternatives
- For each candidate, gather via
/socket-inspect:- Socket score and alerts
- Number of dependencies
- Package size
- Maintenance status (last publish date, open issues)
- Build an API compatibility table showing which APIs from the usage map each candidate supports:
API Compatibility:
| API Used | dayjs | date-fns | luxon |
|-----------------|---------------|---------------|---------------|
| format() | .format() | format() | .toFormat() |
| parse() | dayjs() | parse() | DateTime.fromFormat() |
| diff() | .diff() | differenceIn*()| .diff() |
| add() | .add() | add*() | .plus() |
| isValid() | .isValid() | isValid() | .isValid |
Coverage: dayjs 5/5, date-fns 5/5, luxon 5/5
- Present the comparison and let the user pick a replacement
Suitable when ALL of the following are true:
- The package implements less than ~50 lines of logic
- The package has no or minimal transitive dependencies
- Only 1-3 APIs from the package are used in the codebase
If the package qualifies:
- Propose an inline implementation for each used API
- Show the user the proposed code
- If approved, the inline code will be placed in a local utility file during Step 6
Always ask user approval before proceeding with any strategy.
| Ecosystem | Install Command |
|---|---|
| npm | npm install {package} |
| pnpm | pnpm add {package} |
| yarn | yarn add {package} |
| PyPI | pip install {package} or add to requirements.txt / pyproject.toml |
| Cargo | cargo add {package} |
| Bundler | Add to Gemfile, then bundle install |
| Maven | Add <dependency> to pom.xml, then mvn dependency:resolve |
| NuGet | dotnet add package {package} |
| Go | go get {package} |
For Strategy C (inline), skip this step.
- Strategies A & B: Update all import/require statements to use the new package name and its API surface
- Strategy C: Replace imports with a reference to the new local utility file (e.g.,
import { isOdd } from './utils/is-odd')
For Strategy C, create the local utility file with the inline implementation.
Using the usage map from Step 3, rewrite each call site:
- Rename APIs if the replacement uses different names (e.g.,
moment.format()→dayjs.format()) - Adjust signatures if the replacement has different parameter orders or types
- Handle behavioral differences - note any cases where the replacement behaves differently and add comments or adapter code
| Ecosystem | Removal Command |
|---|---|
| npm | npm uninstall {package} |
| pnpm | pnpm remove {package} |
| yarn | yarn remove {package} |
| PyPI | Edit requirements.txt / pyproject.toml directly to remove the line, then pip install -r requirements.txt or poetry lock |
| Cargo | cargo remove {package} |
| Bundler | Edit Gemfile to remove the entry, then bundle install |
| Maven | Edit pom.xml to remove the <dependency> block, then mvn dependency:resolve |
| NuGet | dotnet remove package {package} |
| Go | Edit go.mod to remove the entry, then go mod tidy |
- Remove
@types/{old-package}if it exists in devDependencies - Install
@types/{new-package}if the replacement needs it and it exists
Update any configuration files that reference the old package:
- ESLint/Babel/Jest/Prettier plugin lists
- Build tool config (webpack loaders, Vite plugins, etc.)
package.jsonscripts that use the package's CLI- PostCSS/Tailwind plugin lists
Follow the standard build & test verification workflow:
- Build the project using its standard build command
- Run the test suite to catch any issues with the replacement
- Search for leftover references to the old package name across the codebase
- If something fails, revert all changes - restore the original package, revert code changes, and report the failure to the user
- Build or tests fail after migration: Check error messages to identify whether the issue is a missing API, a behavioral difference, or a type mismatch. Revert all changes and report the specific incompatibility.
- No suitable replacement found: Report that no alternative meets the criteria. Suggest the user check Socket's package page for more options or consider whether the dependency is truly needed.
- Replacement package has worse Socket score: Warn the user that the replacement may introduce new risks. Let them decide whether to proceed.
- Partial API coverage: If no single replacement covers all used APIs, report the gap and let the user decide - they may want to use multiple packages or inline the uncovered APIs.
socket-optimizenot available: Fall back to Strategy B (manual research).
| Aspect | /socket-dep-cleanup | /socket-dep-replace |
|---|---|---|
| Goal | Remove an unused dependency | Swap a used dependency for an alternative |
| Precondition | Package is (suspected) unused | Package IS used but needs replacement |
| Usage search | Determines IF the package is used | Builds a detailed map of WHAT APIs are used |
| Code changes | Remove dead imports and code | Rewrite imports and call sites to use the replacement |
| Outcome | Fewer dependencies | Same or fewer dependencies, different package |
- For large migrations (many call sites or complex API differences), use subagents to parallelize the rewrite across files
- Run
/socket-scanafter replacement to verify the new dependency's security posture - When replacing a package used across many files, consider creating a thin adapter module first, then swapping the implementation behind it
- For Strategy C (inline), keep the utility file small and well-tested - don't inline complex logic
- If the user isn't sure which replacement to pick, Strategy B's API compatibility table helps make an informed decision