Skip to content

Quickstart

This walks from an empty crate to a method call. The two binaries you use are merod (the node daemon — init, run) and meroctl (the operator CLI — app, context, namespace, call).

  1. Create a library crate with a WASM-compatible crate-type. A minimal Cargo.toml, modelled on apps/kv-store/Cargo.toml:

    [lib]
    crate-type = ["cdylib", "rlib"]
    [dependencies]
    calimero-sdk = { git = "https://github.com/calimero-network/core" }
    calimero-storage = { git = "https://github.com/calimero-network/core" }
    [dev-dependencies]
    # native test harness (TestHost) + CRDT merge under `cargo test`
    calimero-storage = { git = "https://github.com/calimero-network/core", features = ["testing"] }
  2. Write the smallest possible app — a state struct plus one method. This is the shape every Calimero app follows (see SDK macros):

    use calimero_sdk::app;
    use calimero_storage::collections::{LwwRegister, UnorderedMap};
    #[app::state]
    pub struct KvStore {
    items: UnorderedMap<String, LwwRegister<String>>,
    }
    #[app::logic]
    impl KvStore {
    #[app::init]
    pub fn init() -> KvStore {
    KvStore { items: UnorderedMap::new() }
    }
    pub fn set(&mut self, key: String, value: String) -> app::Result<()> {
    self.items.insert(key, value.into())?;
    Ok(())
    }
    #[app::view]
    pub fn get(&self, key: String) -> app::Result<Option<String>> {
    Ok(self.items.get(&key)?.map(|v| v.get().clone()))
    }
    }
  3. Build to WASM. The example apps ship a build.sh; the load-bearing line is:

    Terminal window
    rustup target add wasm32-unknown-unknown
    cargo build --target wasm32-unknown-unknown --profile app-release

    The artifact lands at target/wasm32-unknown-unknown/app-release/<crate_name>.wasm. The example scripts then copy it into a local res/ directory and (if wasm-opt is installed) shrink it:

    Terminal window
    wasm-opt -Oz --enable-bulk-memory ./res/my_app.wasm -o ./res/my_app.wasm
  1. Initialize a node’s config and data directory, then run it:

    Terminal window
    merod --node node1 init --server-port 2428 --swarm-port 2528
    merod --node node1 run

    merod --node node1 init --help lists the full set (swarm/server host and port, boot nodes, mDNS, auth mode). Config and data live under CALIMERO_HOME / --home.

3. Install the app, attach a context, call a method

Section titled “3. Install the app, attach a context, call a method”

meroctl talks to a running node. Select the node with --node node1 (a configured alias) or --api <URL>.

  1. Install the WASM module. The node returns an application id:

    Terminal window
    meroctl --node node1 app install \
    --path ./res/my_app.wasm \
    --package com.example.myapp \
    --version 1.0.0

    List what is installed with meroctl --node node1 app ls.

  2. Attach the app to a context. A context is a running instance of an app over a shared state. The simplest entry is to create a namespace bound to the application id:

    Terminal window
    meroctl --node node1 namespace create --application-id <app-id>
  3. Call a method on the context. Mutations and views both go through the top-level call command — whether a call mutates or is a read-only view is decided by the method’s own #[app::view] marker, not a CLI flag:

    Terminal window
    # mutate
    meroctl --node node1 call set \
    --context <context-id> \
    --args '{"key": "hello", "value": "world"}'
    # view
    meroctl --node node1 call get \
    --context <context-id> \
    --args '{"key": "hello"}'

    --args takes JSON matching the method’s parameters. <context-id> accepts a context id or an alias you created with --name.

These three commands trace one path from a built artifact to a method result — install the code, attach a context over shared state, then call into it: