| name | socket-dep-replace |
| description | Replace a dependency with an alternative package, eliminate it via code rewrite, or use socket-optimize for optimized replacements. |
Dep Replace
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.
When to Use
- The user wants to swap a dependency for a different package (e.g., migrating from
moment to dayjs)
- 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-optimize to find optimized replacements
- The user asks how to migrate away from a specific package
Prerequisites
- Socket CLI - optional but recommended. Required for Strategy A (
socket-optimize). Install via /socket-setup if not available.
- Build and test commands - the project should have a working build and test setup for verification.
Step 1: Identify the Target Package
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-scan first 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.
Step 2: Detect the Ecosystem
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).
Step 3: Search for All Usages
Search the entire codebase for every reference to the target package. Be thorough - check all of the following:
Direct Import/Require Patterns
| 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. |
Indirect Usage Detection
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/node supports 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-react is listed as react in .eslintrc); search config files for the short name
- CLI tools in
scripts - packages that provide binaries referenced in package.json scripts (e.g. rimraf, concurrently, cross-env); check the scripts block
- 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, turbopack and their plugins; check config files
- PostCSS/Tailwind plugins - referenced in
postcss.config.* or tailwind.config.*
- Python entry points and console scripts - packages providing CLI commands configured in
pyproject.toml or setup.cfg
- Bundler groups - gems in
:development or :test groups may only be used in specific contexts
- Cargo build dependencies - crates in
[build-dependencies] are used by build.rs
- Maven plugins -
<plugin> entries in pom.xml are not imported in code
Where to Search
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.json scripts block
- CI/CD configs (
.github/workflows/, .gitlab-ci.yml, etc.)
- Shell scripts (
*.sh)
- Dockerfiles
- Documentation that references the package as a runtime dependency
Build the Usage Map
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
merge for deep object merging", "uses format for 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)
Step 4: Report Findings
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).
Step 5: Determine Replacement Strategy
Present three strategies in priority order. If the user already specified a replacement package, skip to Strategy B with that package pre-selected.
Strategy A: socket-optimize
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.
Strategy B: Research Alternatives via /socket-inspect
- 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
Strategy C: Inline Elimination
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.
Step 6: Execute the Migration
6a. Install Replacement Package (Strategies A & B)
| 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.
6b. Rewrite Import Statements
- 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.
6c. Rewrite API Call Sites
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
6d. Remove Original Package
| 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 |
6e. Handle @types/* Packages
- Remove
@types/{old-package} if it exists in devDependencies
- Install
@types/{new-package} if the replacement needs it and it exists
6f. Clean Up Config References
Update any configuration files that reference the old package:
- ESLint/Babel/Jest/Prettier plugin lists
- Build tool config (webpack loaders, Vite plugins, etc.)
package.json scripts that use the package's CLI
- PostCSS/Tailwind plugin lists
Step 7: Verify
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
Error Handling
- 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-optimize not available: Fall back to Strategy B (manual research).
How This Differs from /socket-dep-cleanup
| 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 |
Tips
- For large migrations (many call sites or complex API differences), use subagents to parallelize the rewrite across files
- Run
/socket-scan after 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