Skip to content

Package & publish

So far the app ran on a development cluster as a raw component (--path). A real cluster installs only signed packages from a registry. A release of your app is a .mpk: a gzip-compressed archive with the app’s component, its built frontend and a signed manifest.json naming the package and version. Every node that runs it checks the signature and the digest of each file before it runs anything.

  1. Build the frontend. The crate’s frontend-dir (../app/dist) is packed into the release, and the cluster serves it from the package’s own origin, so build it first (after pnpm install at the project’s root):

    Terminal window
    pnpm -F kv-store build
  2. Create a signing key, once. The key is your app’s identity: a new version must be signed by the same key, or it is a different app.

    /home/you/.calimero/release.key
    meroctl app signer new ~/.calimero/release.key
    # signerId: did:key:z6Mk...

    meroctl app signer id ~/.calimero/release.key prints the signer id again. Keep the file secret and out of version control: here it lives in ~/.calimero, outside the project, where git add . cannot pick it up.

  3. Pack and sign the release, from the app’s crate:

    Terminal window
    meroctl app pack apps/kv-store/logic --key ~/.calimero/release.key --app-version 1.0.0

    pack reads the crate’s [package.metadata.calimero]: package, min-runtime-version, frontend-dir, and the display metadata the registry lists a new package by (name, description, icon, category, tags, author, …). It builds the component, checks the frontend against the node’s rules, writes and signs manifest.json, and writes apps/kv-store/logic/dist/com.calimero.kv-store-1.0.0.mpk. The version is --app-version, else the crate’s version.

    For every release after the first, pass --previous <last .mpk>: pack then compares the two ABIs, warns about changes that break callers, and refuses a state change made without a state version bump.

  4. Check it as a node does:

    Terminal window
    meroctl app inspect apps/kv-store/logic/dist/com.calimero.kv-store-1.0.0.mpk

    It opens the bundle, checks the signature and every file’s hash, and prints verified, the signerId, the bundleHash and the manifest.

  5. Publish it to the Calimero app registry with a registry API key:

    Terminal window
    export CALIMERO_REGISTRY_API_KEY=...
    meroctl app publish apps/kv-store/logic/dist/com.calimero.kv-store-1.0.0.mpk

    With --org ORG, the key is a Calimero Cloud organization’s API key instead (ck_live_…, scope registry:publish), which meroctl trades at the Cloud for a short publish token. A refusal comes back with the registry’s code (version_not_allowed, invalid_signature, …). You can also upload a .mpk from the Calimero Cloud console’s Registry page.

An app can ship several services in one package: each app instance runs one of them, picked with meroctl instance create --service NAME. A directory of rooms, for example, is a directory service and a room service. Name each service and its crate with --service NAME=PATH (a crate directory, which pack builds, or a built component), and the manifest declares services instead of a single wasm:

Terminal window
meroctl app pack --service directory=crates/directory --service room=crates/room \
--package com.example.rooms --app-version 1.0.0 --key my-signing-key.json

Or list them in the crate’s [package.metadata.calimero] (a workspace root with no [package] of its own uses [workspace.metadata.calimero], and its release is [workspace.package] version), and meroctl app pack DIR packs them with no flags:

[workspace.metadata.calimero]
package = "com.example.rooms"
services = [
{ name = "directory", path = "crates/directory" },
{ name = "room", path = "crates/room" },
]

Each service is packed as services/<name>.wasm, with its compute component and pipelines beside it (--service-compute, --service-pipeline). From core 1.0.0-rc.25; the full rules are in the packaging reference.

A new package is private by default: only the organization that publishes it can deploy it. --public lists it for everyone:

Terminal window
meroctl app publish apps/kv-store/logic/dist/com.calimero.kv-store-1.0.0.mpk --public

A package’s identity is its package id and its signer. A new release signed by the same key under the same package is an upgrade of the existing app; signed by another key, it is a different app, and existing instances do not pick it up. A node also pins a package to the signer of its first release.

The manifest format and the exact checks a node runs on install are in the core reference’s Packaging & signing.

Next → Deploy & install: run the published package on Calimero Cloud or on a node.