AnswerQA

How do I make my plugin depend on another plugin without breaking when they ship a release?

Answer

Declare plugin dependencies with semver ranges in plugin.json, tag releases with the required convention, and configure cross-marketplace trust carefully. The npm source caveat and three error codes are the most common trip points.

By Kalle Lamminpää Verified May 12, 2026

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:

SyntaxMeaning
^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.0Inclusive range
>=2.0.0-beta.1Includes 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’s plugin.json or pinning an intermediate version.
  • dependency-version-unsatisfied: a specific version is installed, but it does not satisfy the declared range. Run claude 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.md instead.
  • 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.

Sources

  • Plugin dependencies
    Canonical reference for the dependencies array schema, semver range syntax, tag convention, cross-marketplace trust, prune commands, and the three dependency error codes.
  • Plugins
    Background on plugin.json schema, marketplace hosting, and the allowCrossMarketplaceDependenciesOn setting context.

Was this helpful?