Skip to content

Publish and upgrade a plugin ​

In Plugin Studio, Deploy, Publish... runs the whole sequence for you (check, snapshot, compile, test, build, install) and offers a rollback: see Create, build, test and publish in Plugin Studio.

What you're doing ​

Getting the .spk onto your ERP and, later, shipping a new version.

The complete sequence ​

bash
# 1. build the .spk (a zip of spk-assembly/)
erp plugin build spk-assembly -o office-equipment-1.0.0.spk

# 2. publish it to the current env, for a tenant
erp plugin publish office-equipment-1.0.0.spk --tenant 2

Output on success:

packaged 33 files -> office-equipment-1.0.0.spk (231986 bytes)
sha256: cef54cdf...
erp plugin publish: office-equipment-1.0.0.spk -> https://erp.example.com (env "dev", tenant 2)
POST .../api/v1/authoring/plugins/upload ...
installed:
{"pluginId":"office-equipment","version":"1.0.0","state":"installed","pf4jState":"STARTED", ...}

"state":"installed" and "pf4jState":"STARTED" mean it's live. The server recomputes the checksum itself — it never trusts the client digest.

What happens on install ​

  1. checksum verified server-side;
  2. the manifest is read (id and version are required; mainClass is optional — a pure-JSON plugin leaves it null);
  3. The platform loads the plugin — lib/*.jar if present, otherwise a built-in generic no-op entry point for a pure-JSON plugin;
  4. entities are created / altered (idempotent-additive);
  5. providers, data views, data services, pages, menus, rules, workflows, i18n and roles are installed;
  6. seed data is upserted;
  7. AFTER_CREATE register rules fire → scheduled jobs register.

If any step fails the whole install rolls back, including the code load.

Version discipline — the rules that will bite you ​

1. Bump the version before every publish ​

plugin.json version must increase. A re-publish of a version that's already installed is a silent no-op — your fix does not ship. Bump it even if you're certain the last publish already contained the change.

2. A version is immutable once stored ​

Once the server has stored office-equipment/1.0.0/office-equipment-1.0.0.spk, re-uploading different bytes under 1.0.0 is rejected:

Refusing to overwrite immutable artifact at "system/plugins/.../1.0.0/..." with different content

A version that genuinely shipped (reached pf4jState: STARTED on some tenant) stays immutable forever — re-publishing different bytes under it is rejected, go to the next version.

But a failed or partial install is not a real release. As of the SDK publish-hardening pass, if a 1.0.0 publish never reached STARTED (it failed later in the pipeline, or it's a metadata-only plugin that isn't code-loaded), re-publishing 1.0.0 replaces the stored .spk and retries — no version bump needed just to fix a broken publish. erp plugin publish of an already-installed id automatically takes the upgrade path, so this "edit a page, re-publish the same version" loop works directly for JSON-only plugins.

3. The platform cannot load two versions of the same plugin id at once ​

There is an already loaded plugin ... with the same id (office-equipment) ...
Simultaneous loading of plugins with the same PluginId is not currently supported.

The publish/upgrade path now reliably stops and unloads the currently-loaded same-id plugin before loading the new bundle (stop → unload → GC hint → load → start), so a normal in-place re-publish never hits this. If an earlier crash or a transient DB error during uninstall left the old code wedged — state: uninstalled in the install row but pf4jState: STARTED in the process — recover without a backend restart:

bash
erp plugin force-unload office-equipment      # clears the stuck code load
erp plugin publish office-equipment-1.0.1.spk --tenant 2

erp plugin publish --force does the force-unload automatically before retrying, and spark publish / erp plugin publish also auto-retry once with a force-unload if they see the "already loaded" error.

These behaviours were all hit while building the tutorial module. Treat version numbers as cheap and monotonic; use force-unload rather than a restart when a load gets stuck.

Roles and names must be unique across installed plugins ​

A plugin.json role whose name or code collides with a role from another installed plugin fails the install:

A role named "Equipment Manager" already exists
Role "..." (code "...") already exists owned by "..."

Prefix your role names and codes with something plugin-specific.

Upgrading ​

bash
# edit files, bump plugin.json version to 1.0.1, rebuild the lib jar if Java changed
erp plugin build spk-assembly -o office-equipment-1.0.1.spk
erp plugin publish office-equipment-1.0.1.spk --tenant 2

Entities gain new columns; pages, rules, seed data are re-installed (upserted). Nothing is dropped — a removed field's column stays, a removed seed row stays.

How to verify it worked ​

bash
erp plugin list

Find your plugin: "version": "1.0.1", "state": "installed", "pf4jState": "STARTED". Then hit a page or an entity endpoint to confirm the new content is live.

Common mistakes ​

SymptomCauseFix
"fix didn't ship"didn't bump version on a shipped versionbump; re-publish. (A failed same-version publish now retries in place.)
Refusing to overwrite immutable artifactretrying a version that already reached STARTED on some tenantgo to the next version
already loaded plugin ... same ida load wedged after a crash / DB bliperp plugin force-unload <id> then re-publish (or publish --force)
role name/code clashanother plugin owns that roleprefix yours