^2.0 or ~2.1.0 that you’ve tested against.
This page is for plugin authors who declare dependencies in plugin.json and for marketplace maintainers who tag releases.
These cases are covered on other pages:
- Installing a plugin that has dependencies: see Manage installed plugins
- Reading a dependency error: see Dependency errors
- Declaring the npm and Bun packages that your plugin’s own code needs: see Node.js package dependencies
Declare dependencies
Without a version constraint, a dependency moves to each new release its marketplace publishes the next time users update. If that release renames an MCP tool your plugin calls, your plugin breaks for everyone who updates. With a constraint such as~2.1.0 on a dependency from a git-backed source, users who have your plugin installed keep receiving 2.1.x patches of the dependency and never move to 2.2. To upgrade on your own schedule, test against a newer release and then publish a new version of your plugin with a wider constraint.
Declare a dependency with a version constraint
List dependencies in thedependencies array of your plugin’s .claude-plugin/plugin.json. The following manifest declares one unversioned dependency and one constrained dependency:
.claude-plugin/plugin.json
"audit-logger" in this manifest, or "name@marketplace" to resolve it in another marketplace. With a bare string, your plugin depends on whatever version that plugin’s marketplace provides.
To set a version constraint, use an object with these fields, each a string:
A range doesn’t match pre-release versions such as
2.0.0-beta.1 unless you opt in with a pre-release suffix such as ^2.0.0-0.
Bundle plugins for a team
To let engineers install a curated set of plugins with one command, publish a plugin whose manifest contains aname and a dependencies array. A plugin manifest needs only name, so this is a valid plugin, and installing it installs every dependency.
For example, a platform team can publish role-specific bundles in an internal marketplace so engineers run one claude plugin install instead of installing each plugin separately:
.claude-plugin/plugin.json
backend-standard version with the extra dependency. When the marketplace doesn’t auto-update by default, engineers either turn on auto-update for the marketplace or update manually:
- Turn on auto-update for the marketplace: the next auto-update moves the bundle to the new version and installs any dependencies it adds.
- Update manually: run
claude plugin update backend-standardin a shell, then/reload-pluginsin an open session to install the newly added dependencies.
enabledPlugins in managed settings. See Pre-install and require plugins.
Depend on a plugin from another marketplace
By default, Claude Code doesn’t install a dependency from a different marketplace than the declaring plugin’s own, unless the user already has that dependency installed and enabled at the same scope. This default prevents one marketplace from silently installing plugins from a source the user hasn’t reviewed. To allow the install, add the target marketplace’s name toallowCrossMarketplaceDependenciesOn in the root marketplace’s marketplace.json. The root marketplace is the one that hosts the plugin the user is installing. Only the root marketplace’s allowlist applies.
The following marketplace.json allows deploy-kit to depend on a plugin from your-shared-marketplace:
.claude-plugin/marketplace.json
allowCrossMarketplaceDependenciesOn is missing or doesn’t include the target marketplace, Claude Code doesn’t install the dependency. When the dependency is declared in the marketplace entry, the install itself is refused with a message that starts Dependency "audit-logger@your-shared-marketplace" (required by deploy-kit@your-marketplace) is in marketplace "your-shared-marketplace", which is not in the allowlist and names the field to set. When it’s declared in plugin.json, the install completes without the dependency and your plugin then fails to load.
The allowlist check doesn’t apply to a dependency that is already enabled. If a user installs audit-logger from your-shared-marketplace themselves first, at the same scope, deploy-kit then installs without any change to the allowlist.
Test a plugin and its dependency locally
If you’re developing a plugin and the plugin it depends on at the same time, start Claude Code from your shell and load both with--plugin-dir:
- No
versionneeded: the localplugin.jsondoesn’t need aversioneither, because a version constraint isn’t checked against a local copy. - Entries that name a marketplace: an entry that names a marketplace also matches the local copy on Claude Code v2.1.242 or later.
- You disabled the local copy: your plugin is disabled at the next plugin load, with an error that ends
is disabled — enable it or remove the dependency. When the error names the dependency as<name>@inline, that identifier refers to the--plugin-dircopy. - You started a session without the dependency’s
--plugin-dirflag: the error reports the dependency as not installed. Pass the flag again, or install the dependency from its marketplace.
--plugin-dir once. If the folder isn’t itself a plugin, Claude Code loads each child folder that has a .claude-plugin/plugin.json. Requires Claude Code v2.1.265 or later.
Release a plugin that others depend on
If you maintain a plugin that other plugins depend on with a version constraint, tag its releases so those constraints can resolve. A constraint resolves against git tags on the repository that hosts the plugin. Tag the repository that the plugin’s plugin source inmarketplace.json points at:
github,url, orgit-subdirsource: the plugin’s own repository, so the plugin’s author creates the tags- Relative path such as
./plugins/secrets-vault: the marketplace repository, so the marketplace maintainer creates the tags
Create a release tag
Tag each release as<plugin-name>--v<version>, where <version> matches the version field in that commit’s plugin.json. The plugin-name prefix lets one marketplace repository host several plugins with independent version histories.
Create the tag from the plugin directory, with an origin remote configured to receive the pushed tag, using claude plugin tag:
- Validates the plugin
- Checks that
plugin.jsonand the marketplace entry agree on the version, when the plugin directory is inside a marketplace checkout - Requires a clean working tree under the plugin directory
- Refuses if the tag already exists
Created tag secrets-vault--v2.1.0. With --push, it also prints Pushed to origin. Without --push, it prints the git push command to run yourself.
Pass --dry-run to see the plan without creating anything.
The claude plugin tag reference lists the remaining flags.
You can also run git tag secrets-vault--v2.1.0 directly, as long as you keep the version in plugin.json and in the marketplace entry in sync yourself.
Constrain a dependency that has a non-git source
Tag-based resolution applies only to git-backed sources. For a dependency with annpm, archive, or command plugin source, the constraint doesn’t control which version is fetched. It’s still checked when the plugin loads, and the dependent plugin is disabled if the installed version doesn’t satisfy it.
For npm, archive, and command sources, the version checked is the version in the dependency’s plugin.json. Set one there before you constrain that dependency, because a plugin.json that sets no version satisfies no constraint.
Claude Code never installs a dependency with a command source itself, so users install it first. It also never runs a dependency’s headersHelper, so users also install a dependency whose marketplace entry sets one before they install your plugin.
Besides claude plugin install, these operations also install any missing declared dependency, and the command and headersHelper limits apply to them too:
/reload-plugins- Auto-update of the dependent plugin’s marketplace
- Re-running
claude plugin installon the dependent plugin claude plugin marketplace add
How dependencies behave for your users
These sections describe how Claude Code resolves, checks, and combines the constraints you declare once your plugin is installed alongside others.How a constraint resolves against tags
When a user installs a plugin that declares{ "name": "secrets-vault", "version": "~2.1.0" }, the dependency installs from the highest secrets-vault--v tag that satisfies ~2.1.0 on the repository that hosts secrets-vault. When no tag satisfies the range, the install either fails or uses the marketplace’s current copy:
- Plugin with its own repository: the install fails with a message containing
Dependency "secrets-vault@your-marketplace" has no git tag satisfying. - Plugin referenced by a relative path: the install uses the marketplace’s current copy instead, and the constraint is checked when the plugin loads. If that copy is outside the range, the dependent plugin stays disabled and
claude plugin listshowsRequires "secrets-vault@your-marketplace" ~2.1.0, installed 3.0.0.
Confirm the resolved version
To confirm which version a constraint resolved to, runclaude plugin list in your shell. A tag-resolved dependency shows its version with a 12-character commit suffix, such as 2.1.0-8713c5b11005.
Constraint checks use the tag’s version rather than the version in plugin.json, even if plugin.json at that commit lags behind.
If you force-move a tag to a different commit, the next install fetches that commit’s content instead of reusing a stale cached copy. See Versions and updates for how a plugin’s version becomes its cache key.
Combine constraints from several plugins
When several installed plugins constrain the same dependency, the dependency resolves to the highest version that satisfies all of their ranges. Common combinations resolve like this:
Auto-update fetches a constrained dependency at the highest git tag that satisfies every installed plugin’s range, rather than at the marketplace’s latest version. If the installed plugins’ ranges don’t overlap, auto-update leaves that dependency at its current version, and the
/plugin Errors tab shows an entry naming the constraining plugin. If they overlap but no tag falls in the range, auto-update fetches the marketplace’s current copy and skips the update when that copy’s version falls outside any installed plugin’s range.
When a user uninstalls the last plugin that constrains a dependency, the dependency is no longer constrained to a version range and resumes tracking its marketplace entry on the next update.
See also
claude plugin prune: remove auto-installed dependencies no plugin needs anymore- Host a marketplace: release channels and recommending other plugins