Why apps cannot collide

Two revenexx Apps cannot break each other. The four boundaries that make that true, what you can therefore skip, where apps do legitimately meet, and what the platform guarantees at each meeting point.

You do not have to check whether your app overlaps with anyone else's. Two apps on the same tenant cannot break each other. No naming coordination with other vendors, no load order, no defensive code against a plugin you have never seen.

This page is for developers who have been burned by plugin conflicts elsewhere and want to know why the same risk does not exist here. It states the guarantee, walks through the boundary that makes it hold, and is honest about the places where apps do meet and what is and is not guaranteed there.

The guarantee

Your app's tables, routes, events, settings and admin screens belong to your app. Another app cannot read your tables, alter your schema, answer on your routes, or change what your code sees. The only way into your app is the capabilities you publish, and the only way out is the capabilities you have declared you will call.

Concretely, the following are not your problem:

You might expect toYou do not, because
Prefix your table names so they do not clash with another vendor'sEvery table is namespaced by your vendor and app name. Two apps can both own an orders entity.
Check whether another app already uses a URLEvery route lives under your app's own prefix, and the gateway routes by it.
Worry about load order or hook priorityThere is no hook chain. Nothing runs inside your process but your code.
Guard against another app's exception taking your route downAnother app's failure reaches you only as an HTTP status on a call you made.
Coordinate event namesAn event is published as <vendor>.<app>.<name>, so serial.registered in two apps are two events.
Fear an upgrade of one app silently changing anotherContracts are versioned strict-forward. A breaking change is a new capability key on a new route.

Why it holds

The guarantee is not a policy. It follows from four boundaries, each of which you can verify from your own manifest and from the errors the platform returns.

1. Your schema is private

Every entity in your schema.json becomes a table named {vendor}__{app}__{entity}, so acme/serials declaring device_serials produces acme__serials__device_serials. Nothing you declare can land on another app's name.

The privacy runs the other way too. A references block that names another app's entity is rejected when the app is applied, and no entry in manifest.permissions can name another app's entity at all. The one thing another app can see of your data is what you put in a lookup block, and that is only the label and the columns you list.

So one app's schema change can never break another app's tables, and no app can be blocked from deleting a row by a foreign key it has never heard of. See Relationships.

2. Nothing reaches your code except through the gateway

Your function has no address anyone can call directly. The public gateway at api.revenexx.com is the only entry, and it forwards a request to your app only when the request matches a route your manifest.capabilities.json declares. An undeclared route in your function is unreachable from outside, and a declared one is served under your app's own prefix.

The same is true of the other direction. Your app gets no access by default. To call another app you declare a capability grant, and an undeclared call is refused. The merchant sees that grant on the consent screen at install time. See Permissions and Calling another app.

3. Every invocation is one tenant, and one that installed you

Your function is invoked for a tenant only when that tenant has your app installed and active. The tenant comes from the request context the gateway verified, never from a header or body a caller could forge, and every read and write your code performs is scoped to that tenant by the platform. There is no query you can write that forgets it, and there is no query another app can write that reaches your rows. See Tenant isolation.

4. Apps do not share a process

Each app deployment runs in its own runtime, per tenant, with its own CPU and memory allocation and its own execution timeout. There is no shared process, no global namespace, and no shared library another app's upgrade could break underneath you. When another app fails or runs out of time, you see it as a failed response to the call you made, and nothing else changes for you. See Whose fault is it.

Compared with the plugin model

If you have shipped plugins for Shopware, Magento or WordPress, the mental model you bring is the one to unlearn:

Plugin platformsrevenexx Apps
Plugins share one database and one schema; a table name is a global claimTables are namespaced per app; the schema is private
Plugins share one process; an uncaught exception in one takes the page downEach app is its own function; failure is an HTTP status the caller handles
Behaviour is composed through hooks, so load order and priority matterBehaviour is composed through capabilities and events; there is no order to get right
Two plugins patching the same class conflict, and the merchant finds out in productionBehaviour is replaced through an explicit, per-tenant override of a versioned contract; the contract itself never changes
A plugin can read and write any table it can nameAn app reads its own tables and reaches other apps only through declared, consented capability grants

Where apps do meet, and what is guaranteed there

Isolation does not mean apps ignore each other. They compose. Each meeting point is deliberate, and each has a stated guarantee and a stated limit.

Capability calls. The interface between two apps is the contract in manifest.capabilities.json: route, request shape, response shape, declared statuses. Versioning is strict-forward, so a published contract may gain things and never change the meaning of what it already published. What is not guaranteed is that the other app is answering. Installed is not the same as available, so handle a 502 as a 502. See Versioning.

Overrides. An app can implement a capability another app defined, and for the tenants that install it the gateway routes that one contract to the new implementation. The contract does not change, and every caller keeps working unchanged. No shipped app uses an override yet, and how two installed implementers of the same key on one tenant are resolved is one of the details that will firm up with the first real use. See Overriding a capability.

Events. Names are unambiguous across the platform because they carry the emitter's vendor and app. Delivery semantics, such as ordering and retries, are not settled enough to document, so write handlers that survive a duplicate, a reorder and a missing event. See Events you receive.

Dependencies. A semver range in dependencies guarantees the other app is installed when yours is activated, and a deploy whose dependencies cannot be satisfied is refused rather than warned about. It does not stop a merchant uninstalling it later, and it gives you no access to its tables. See Dependencies.

App identity. vendor/app is unique across the platform. A second app claiming the same vendor and name is refused, never merged, and the vendor slug belongs to your organisation. Within your vendor, naming is yours alone.

The Cockpit sidebar. Every installed app's cockpit.json is merged into one interface, ordered by group and position. An app that claims a navigation id owns it; another app may attach children under it. Two apps claiming the same id is a conflict the Cockpit reports rather than resolves. See How the Cockpit renders.

Scope dimensions. A dimension such as market has exactly one provider platform-wide. A second app declaring the same dimension is rejected. See Scoping.

Business meaning. Two apps on one tenant can both act on the same business fact through capabilities, for example two apps that adjust stock. The platform guarantees each call is authorised and scoped; it does not arbitrate which app is right about the business. That remains a design question for the tenant and the apps it installs.

What this page does not describe

The runtime machinery behind these boundaries is not part of the contract you build against, and it is not documented here. What is documented is the behaviour you can rely on and the errors you will see when a boundary is crossed: a rejected cross-app reference when the app is applied, a refused undeclared capability call, a null for another tenant's row, a reported Cockpit conflict.

Next steps

Was this page helpful?