Dependencies

Declaring the apps yours needs — dependencies installed automatically versus peerDependencies the merchant is prompted for, semver ranges, and the vendor/app key rule.

An app can need another app. There are two blocks for saying so, and the difference is who installs it.

manifest.json
"dependencies": { "revenexx/markets": "^0.1", "revenexx/orders": ">=0.6" },
"peerDependencies": { "revenexx/prices": "^1.0" }
BlockInstalled howUse for
dependenciesAutomatically, when your app is activated for a tenantApps yours genuinely cannot run without
peerDependenciesThe merchant is prompted and installs it themselvesPaid or genuinely optional dependencies

Which block

dependencies is for something your app is broken without. A market-scoped setting needs the markets app; an entity scoped by market needs it too. Declaring it means the merchant never ends up with your app installed and its foundation missing.

peerDependencies is for a dependency that is a genuine decision. Use it when the dependency costs money, when the merchant may already have a competing app filling that role, or when your app degrades gracefully without it. The merchant gets a prompt rather than a silent install and a surprise line on an invoice.

The test: would installing this app on the merchant's behalf, without asking, ever be the wrong thing to do? If yes, it is a peer.

The key rule the JSON Schema does not enforce

Keys must be vendor/app.

manifest.json
"dependencies": {
  "revenexx/markets": "^0.1"
}
Rejected
"dependencies": {
  "markets": "^0.1"
}

A bare app name is rejected when the app is applied — not when the JSON Schema validates it. The schema sees a valid object with a string value, so your editor is happy, npm test is happy, and the failure arrives during the deploy.

This is the single most common manifest mistake, and it costs a build every time. Check both blocks before you deploy: every key has exactly one slash, the part before it is a vendor slug, and the part after it is an app name.

revenexx is the vendor for platform apps. Your own apps use your organisation's slug.

Version ranges

Values are semver ranges. The usual operators apply:

RangeAccepts
^0.1Compatible releases up to the next major
~1.2.0Patches of 1.2 only
1.0.0Exactly that version
>=0.6That version or anything newer

Prefer ^. It picks up fixes and features and stops at the next major, where breaking changes are allowed to land. An exact pin never changes underneath you and also never gets a fix until you bump it by hand — and a routine patch in a dependency leaves you demanding a version nobody ships any more.

>= with no upper bound is the opposite risk: it accepts a future major whose breaking changes you have never seen.

A dependency is a runtime relationship, not a data one

Declaring a dependency does not give you access to that app's tables, and it does not let you write a foreign key across the boundary. Those are rejected. See Relationships.

Reaching another app is always its capabilities, and calling one always needs its own grant:

manifest.json
"dependencies": { "revenexx/orders": ">=0.6" },
"permissions": [
  { "capability": "orders.get", "compatible": "^1.0" }
]

Those two lines do different jobs and you usually need both:

  • dependencies makes sure the app is there.
  • permissions makes you allowed to call it, and puts it on the merchant's consent screen.

A grant without a dependency is an app that works on tenants that happen to have the other app installed and fails on the rest. A dependency without a grant is an app that is installed and unreachable.

Practical guidance

Declare the fewest dependencies you can. Each one is another app in the merchant's tenant, another version range to keep current, and another thing that can be uninstalled underneath you.

Handle the dependency being unavailable anyway. Installed is not the same as answering. A capability call that fails is a 502 you translate, not an exception that takes your route down. See Calling another app.

Do not depend on an app for one field. If all you need from another app is a label for an id, a lookup resolves it in the UI with no dependency and no call at all.

Re-read both blocks before a major. A dependency you no longer use is a grant you no longer need and a prompt the merchant no longer has to answer.

Next steps

Was this page helpful?