Run Any Language on Acurast
Node.js was never the limit. With Cargo, if it runs on Linux, it runs on Acurast — Python, Go, Rust, Java, and everything else.
For a long time, deploying to Acurast meant writing JavaScript. The processors run Node.js, and that runtime is a great fit for a huge class of workloads: oracles, bots, scrapers, API glue. But it was also a ceiling. If your workload was a Python ML script, a Go networking daemon, or a Rust binary, you were out of luck.
Cargo removes that ceiling. It is Acurast's Shell runtime: instead of handing your code to a JavaScript engine, the processor boots a full Linux image, mounts your files, and runs an entrypoint script inside it. From there, you are no longer deploying "a Node.js app" — you are deploying a Linux workload. And a Linux workload can be written in any language you like.
If it runs on Linux, it runs on Acurast.
To prove it, we built the same tiny program in ten different languages and deployed every one of them to the network. Each example lives in acurast-example-apps and does exactly one thing: POST a small JSON payload to a webhook, tagged with the language it came from. Boring on purpose — the interesting part is that the same deployment model carries all ten.
How Cargo works
A Cargo deployment is just a directory of files plus an entrypoint. Three things make it tick, all declared in acurast.json:
{
"runtime": "Shell",
"image": {
"url": "https://github.com/termux/proot-distro/releases/download/.../ubuntu-questing-aarch64-pd-v4.30.1.tar.xz",
"sha256": "5ab35b90cd9a9f180656261ba400a135c4c01c2da4b74522118342f985c2d328"
},
"fileUrl": "app",
"entrypoint": "start.sh"
}
runtime: "Shell"tells the processor to run a script, not a JS bundle.imageis aproot-distroLinux rootfs (here, Ubuntu onaarch64) — pinned bysha256so every processor runs the exact same bytes.fileUrlis the directory uploaded as your cargo;entrypointis the script run inside the rootfs.
The processor downloads the image, mounts your app/ directory, and runs start.sh. Everything after that is up to you. For the full walkthrough, see the Cargo Quickstart and the Cargo runtime reference.
The pattern: bring your own toolchain
Every language example follows the same three-step shape inside start.sh:
- Prepare the rootfs — set
PATH/HOME, pointTMPDIRat a writable dir, and configure DNS. - Install the toolchain —
apt-get installthe interpreter or compiler (or download a prebuilt tarball when apt doesn't carry it). - Run the program.
For an interpreted language like Python, that's nearly trivial — install and run:
apt-get install -y python3-requests
python3 "$SCRIPT_DIR/main.py"
A compiled language adds one step: build, then run. Go installs from apt and compiles on the device:
apt-get install -y golang-go
export CGO_ENABLED=0 # pure-Go DNS + runtime; no C toolchain needed
go run "$SCRIPT_DIR/main.go"
And when a language isn't reliably packaged, you just fetch the official build — exactly what you'd do on any Linux box. Zig, for example:
ZIG_VERSION=0.13.0
curl -fsSL "https://ziglang.org/download/${ZIG_VERSION}/zig-linux-aarch64-${ZIG_VERSION}.tar.xz" -o "$HOME/zig.tar.xz"
tar -C "$HOME" -xf "$HOME/zig.tar.xz"
export PATH="$HOME/zig-linux-aarch64-${ZIG_VERSION}:$PATH"
zig build-exe "$SCRIPT_DIR/main.zig" -lc -lcurl -femit-bin="$HOME/zig-app"
"$HOME/zig-app"
That's the whole trick. There is no special integration — apt, curl, and tar are the integration. If you can install it on Linux, you can run it on Acurast.
Per-language starting points
The repository ships the same webhook program in each language below. Same acurast.json shape, same start.sh skeleton — only the toolchain line differs. Pick the one closest to your stack, swap in your own program, and deploy.
C++
Installs g++ from apt, compiles main.cpp on the device, and runs the binary.
apt-get install -y g++ libcurl4-openssl-dev
Example: app-cargo-cpp
C#
Uses the Mono compiler and runtime from apt.
apt-get install -y mono-mcs mono-runtime
Example: app-cargo-csharp
Go
Installs the Go toolchain from apt and compiles on the device. CGO_ENABLED=0 keeps it pure-Go, so no C toolchain is needed.
apt-get install -y golang-go
export CGO_ENABLED=0
go run "$SCRIPT_DIR/main.go"
Example: app-cargo-go
Java
Installs the default JDK and runs a single source file directly (java Main.java).
apt-get install -y default-jdk
java "$SCRIPT_DIR/Main.java"
Example: app-cargo-java
Node.js
Cargo can also run Node.js as an ordinary Linux workload — install it from apt like any other toolchain.
apt-get install -y nodejs
Example: app-cargo-nodejs
PHP
Installs the PHP CLI and cURL extension from apt.
apt-get install -y php-cli php-curl
Example: app-cargo-php
Python
Installs the interpreter (with requests) from apt and runs the script — the simplest possible case.
apt-get install -y python3-requests
python3 "$SCRIPT_DIR/main.py"
Example: app-cargo-python
Ruby
Installs Ruby from apt and runs the script.
apt-get install -y ruby
Example: app-cargo-ruby
Rust
Installs current stable Rust via rustup (apt's rustc is too old for some crates), then builds and runs.
curl -fsSL https://sh.rustup.rs | sh -s -- -y
Example: app-cargo-rust
Zig
apt doesn't carry Zig, so the example fetches the official prebuilt tarball, then compiles and runs.
ZIG_VERSION=0.13.0
curl -fsSL "https://ziglang.org/download/${ZIG_VERSION}/zig-linux-aarch64-${ZIG_VERSION}.tar.xz" -o "$HOME/zig.tar.xz"
tar -C "$HOME" -xf "$HOME/zig.tar.xz"
Example: app-cargo-zig
Seeing what happened
One catch comes with running off-device: the processor's stdout and stderr aren't accessible to you. So the examples include an optional debug block in start.sh that POSTs lifecycle and error reports to your webhook — startup, done, and on failure an error with the stage, exit code, and a tail of stderr:
report() {
curl -sS -X POST "$WEBHOOK_URL" -H "Content-Type: application/json" \
-d "{\"language\":\"python\",\"status\":\"$1\"${2:+,$2}}" >/dev/null 2>&1 || true
}
It is not required — the program already POSTs on success — but it turns a silent failure into a readable one. Strip it out once your workload is stable for a minimal deployment.
Deploying it yourself
Every example deploys the same way:
cp .env.example .env # set ACURAST_MNEMONIC and WEBHOOK_URL
npm i
npm run deploy
The CLI uploads your app/ directory, the processor pulls the pinned image, mounts the cargo, and runs start.sh. Within seconds your Python — or Rust, or Zig — is running on a real device somewhere on the network, POSTing back to your webhook.
Why this matters
For builders, Cargo means you stop bending your workload to fit the platform. Bring the language, libraries, and binaries you already use. The deployment model is the same regardless of what's inside — which means the thing you learn once carries across every project you ship.
For the network, it widens the front door. The set of workloads that can run on Acurast is no longer "things expressible in JavaScript" — it's "things that run on Linux." That's most of the software ever written.
Node.js was the start. Cargo is what comes after.