The dependencies array in plugin.json lets one plugin require another at a specific version. Without it, two teammates can install different versions of a shared utility plugin and get different behavior. With it, Claude Code resolves the full dependency graph at install time and refuses to load an incompatible combination.
Declare a dependency
In your plugin’s plugin.json, add a dependencies array:
{
"name": "my-formatter",
"version": "1.3.0",
"dependencies": [
"shared-utils",
{ "name": "audit-logger", "version": "^2.0.0" },
{ "name": "code-standards", "version": "~1.4.0", "marketplace": "https://github.com/acme/internal-plugins.git" }
]
}
A bare string ("shared-utils") pins to whatever is currently installed or the latest available. An object form lets you specify a semver range and, optionally, which marketplace to pull the dependency from.
Supported range syntax:
| Syntax | Meaning |
|---|---|
^2.0.0 | >=2.0.0 <3.0.0 (compatible patch + minor) |
~1.4.0 | >=1.4.0 <1.5.0 (patch only) |
1.2.0 - 1.5.0 | Inclusive range |
>=2.0.0-beta.1 | Includes prerelease; required to match beta tags |
Tag releases so ranges can resolve
Claude Code resolves ranges against git tags. The required tag format is {plugin-name}--v{version}:
# After incrementing version in plugin.json:
claude plugin tag --push
This creates and pushes a tag like my-formatter--v1.3.0. Without it, the dependency resolver has nothing to match against and will throw no-matching-tag.
If you host the plugin on npm instead of a git-based marketplace, constraints are checked at load time but the resolver cannot fetch a specific version. The npm source always installs the latest matching semver on the registry, not the version Claude Code pinned.
Allow cross-marketplace dependencies
By default a plugin can only depend on plugins from the same marketplace. To let plugins pull dependencies from a second marketplace, add this to your managed settings or user settings:
{
"allowCrossMarketplaceDependenciesOn": [
"https://github.com/acme/shared-plugins.git"
]
}
Trust does not chain. If marketplace A is allowed to pull from marketplace B, and marketplace B depends on something in marketplace C, that does not make marketplace C trusted. You must list every trusted source explicitly.
Remove orphaned dependencies
Uninstalling a plugin does not automatically remove its dependencies. Run claude plugin prune to identify and remove plugins no other installed plugin depends on:
claude plugin prune
To remove automatically on uninstall without being prompted:
claude plugin uninstall shared-utils --prune
--prune requires Claude Code v2.1.121 or later.
Footguns
When dependency resolution fails, the error code tells you exactly what went wrong. Three errors, three different causes:
range-conflict: two plugins require the same dependency at incompatible ranges. Neither installs until you resolve the conflict by updating one plugin’splugin.jsonor pinning an intermediate version.dependency-version-unsatisfied: a specific version is installed, but it does not satisfy the declared range. Runclaude plugin update <dependency-name>to pull a compatible tag.no-matching-tag: the marketplace has no git tag matching the{name}--v{version}convention for the required range. The dependency author needs to tag their releases correctly.
npm sources do not pin versions. Claude Code checks the constraint at load time but cannot fetch a specific npm version. If a dependency ships a breaking change under the same semver range (prerelease or yanked-and-re-released patch), npm delivers whatever is latest. For stable internal tools, prefer git-based marketplaces over npm.
Prerelease versions require opt-in. A range of ^2.0.0 will not match 2.1.0-beta.1 even if it is the only available tag above 2.0.0. Use >=2.0.0-beta.1 or specify the exact prerelease version to include it.
Cross-marketplace trust is not transitive. If your plugin depends on a plugin from a trusted external marketplace, and that plugin has its own dependencies on a third marketplace you have not listed, the install fails. Check the full dependency tree before adding external marketplace dependencies.
When NOT to use plugin dependencies
- You want to share code, not configuration. Plugin dependencies wire up Claude Code extensions. For shared TypeScript utilities or runtime libraries, use a normal package manager like npm or bun.
- The dependency is just a CLAUDE.md snippet. Embedding a short instruction set as a dependency adds install overhead; include it in your plugin’s own
CLAUDE.mdinstead. - You need the dependency at a specific commit, not a semver range. The resolver only matches tags following the
{name}--v{version}convention. Arbitrary commit references are not supported.