Packaging & signing your app
Once your app compiles, it still has to become something a node can install. That
deliverable is an .mpk bundle: a single archive carrying your WASM, its ABI,
the state schema, a manifest.json, and an Ed25519 signature. This page walks the
builder workflow that produces one.
The signing tool is mero-sign (tools/mero-sign/). The node side — how a bundle
is parsed, verified, and trusted on install — lives in
Upgrades & migration; this page does not duplicate that
detail.
The workflow
Section titled “The workflow”-
Build the WASM and extract the ABI.
Compile your app to
wasm32-unknown-unknown, then produce the ABI artifacts. The ABI manifest (methods, events, types) and the state schema are generated from your annotated source at build time — see App interface (ABI).Terminal window ./build.sh # compile to wasm32-unknown-unknowncalimero-abi extract app.wasm \--output bundle-temp/abi.json # the full ABI manifestThe bundle directory ends up holding the WASM,
abi.json, an optionalstate-schema.json, and themanifest.jsonyou sign in step 3. Most apps wrap all of this in abuild-bundle.shscript. -
Generate a signing key (one-time).
mero-sign generate-keycreates an Ed25519 keypair and derives your signer id — adid:keyidentifier built from the public key (the0xed01ed25519-pub multicodec tag plus the 32-byte key, base58btc-encoded under thedid:key:prefix).Terminal window mero-sign generate-key --output my-signing-key.json# Generated new keypair: my-signing-key.json# signerId: did:key:z6Mkrb81NKkv7Mw4dZAWA5PTuwBhbq9u9eCPuby3icBUdirgThe key file is JSON with base64url-encoded
privateKeyandpublicKeyplus the derivedsignerId. Keep it secret and out of version control — it is your update authority (see below). -
Sign the manifest and create the
.mpk.Point
mero-sign signat yourmanifest.json. It derives thesignerIdfrom the key, setsminRuntimeVersionif absent, canonicalizes the manifest with RFC 8785 (JCS), signs the SHA-256 of those canonical bytes, and writes asignatureobject back into the manifest. It then packages the bundle directory into an.mpk.bundle-temp/manifest.json mero-sign sign bundle-temp/manifest.json --key my-signing-key.json# signerId: did:key:z6Mkm9KCceaDHiwAuYM7y3HteaCHSEkPzACySDkqkXTK6nWd# Bundle created: res/kv-store-1.0.0.mpkThe resulting
.mpkis a gzip-compressed tar archive whose required entry ismanifest.json, alongside the WASM, ABI, state-schema, and migration artifacts the manifest references. -
Install with
meroctl.Terminal window meroctl --node node1 app install \--path res/kv-store-1.0.0.mpk \--package com.calimero.kv-store \--version 1.0.0The node reads
manifest.jsonstraight out of the archive and verifies the signature before admitting the app. Installing the bundle is what produces an application: the manifest’spackageandsignerIdfix the application id.
The signer key is the update authority
Section titled “The signer key is the update authority”For a bundle, the application id is derived from the package and the
signerId together — not from the bytecode. That makes the application id
version-stable: a new release signed by the same key under the same
package keeps the same application id and is recognized as an upgrade of the
existing app.
The corollary is the rule to remember: a new signed version must use the same signer key. Sign a new release with a different key and the node computes a different application id — it is a different application, not an upgrade, and existing contexts will not pick it up. Treat the signing key as the long-lived identity of your app and guard it accordingly.