Purpose
This documentation is intended for developers and users of zela.io and serves as a central reference for understanding how to work with the platform.
The goal of this documentation is to:
- provide a high-level understanding of how zela.io is structured,
- explain how to deploy and manage procedures,
- describe how to debug common issues,
- outline support workflows,
- clarify the terms of platform usage.
The documentation focuses on practical usage and operational concepts rather than internal implementation details. It is suitable for both new users onboarding to zela.io and experienced users looking for a consistent reference.
Introduction
zela.io is a platform for deploying and executing Solana procedures in a controlled and scalable environment.
Zela lets you send a procedure to run next to the current Solana block producer, so your application gets the full workflow outcome in a single call instead of many separate RPC requests.
Think of it as a Solana-compatible JSON-RPC layer where you can deploy custom procedures that run in Zela’s execution environment and interact with Solana RPC nodes on your behalf.
In Zela terminology, a procedure is a unit of user code that implements the CustomProcedure trait and can be invoked via JSON-RPC.
Benefits
- Latency-critical, multi-step workflows can run as one tight loop next to the block producer
- Lower end-to-end latency for real workflows, not just for individual transactions.
- Latency is not only reduced but much more stable/predictable
- Higher reliability: fewer broken chains of RPC calls, fewer expired quotes, fewer user-visible errors.
Architecture Overview
zela.io is built as a set of specialized modules that work together to build, execute, and expose procedures. Each component has a clear responsibility, which helps keep the platform reliable, scalable, and easier to operate. At a high level, the platform consists of the following core components:
Builder
The Builder module is responsible for turning source code into WebAssembly procedure artifacts.
It handles:
- fetching source code from the configured Git repository,
- compiling procedures from Rust to WebAssembly,
- storing build artifacts,
- exposing a build result with a clear status (Pending, Building, Success, Error or Cancel).
Only successfully built procedures can be executed by the platform.
Executor
The Executor module is responsible for running built procedures in an isolated execution environment.
It handles:
- instantiating WebAssembly into native code,
- executing procedures on incoming requests,
- caching instances to avoid cold start latency,
- isolating execution from other workloads,
- collecting execution-related metadata (logs, traces, metrics).
The Executor ensures that procedures run in a controlled and predictable manner and that they run as fast as possible.
The Executor isn’t a singular instance. It is deployed in multiple geographical locations corresponding to Solana hotspots - places where existing Solana traffic is concentrated. This aims to that your procedures run as close as possible to the Solana Leaders and receive the most up-to-date state.
Solana proxy
The Solana proxy module provides access and smart selection of upstream Solana RPC nodes.
It is used to:
- call built-in Solana RPC methods from custom procedures,
- track upstream health and latency,
- pick the upstream to serve individual subrequests.
The Solana proxy enables that each time a procedure requires data it reaches out to the upstream with the lowest round-trip latency from the Executor server.
Dashboard & API Layer
The Dashboard and API layer provide the main interface to the zela.io platform.
They are used for:
- managing projects and sources,
- triggering and monitoring builds,
- viewing build and execution logs,
- managing permissions and access.
This layer is designed to support both human users (via the Dashboard UI) and programmatic access (via APIs).
Component Interaction (High Level)
At a high level, the interaction flow is as follows:
- A procedure source is configured via the Dashboard.
- The source points to a branch in a GitHub repository.
- This configuration is stored in the Core service.
- The Builder compiles and validates the procedure source.
- The Builder is able to access the GitHub repository thanks to access granted through our GitHub App.
- The build is performed in a containerized environment and the build logs are available in the Dashboard.
- The output WebAssembly artifact is stored in our database.
- A successful build becomes available for execution.
- The identifier is the git commit hash, so you always know which source code you are running.
- The JSON-RPC
methodname is alwayszela.PROCEDURE_NAME#COMMIT_HASHtogether with an appropriate JWT authentication token.
- The Executor runs the procedure on demand.
- Performing a JSON-RPC call to the executor triggers a load to cache.
- The WebAssembly artifact is loaded and compiled to native code on the Executor itself.
- The Dashboard exposes logs and metadata.
- Runtime logs are available for each revision.
Deploying a Procedure
This section describes the high-level steps required to deploy a procedure on zela.io, from source configuration to a successful build.
Creating a Procedure Source
To deploy a procedure, a source must first be created within a project. Your first and default project is created during the onboarding.
A source defines how WASM artifacts are materialized in Zela. We support automatic builds from GitHub and manual uploads of WASM artifacts.
For GitHub the configuration includes:
- the Git repository where the procedure code is stored,
- the branch to build from,
- the (Cargo) package name.
The Git repository must be a Rust Cargo workspace or a crate. Linking a GitHub repository is optional.
Once a source is created, it becomes the basis for building and deploying procedures on the platform.
Triggering a Build
After a source is configured, a build can be triggered to compile and validate the procedure.
Builds are triggered on push events to your GitHub repository (filtered by the configured branch) and automatically when creating the source in the Dashboard UI. If you have not linked a GitHub repository to your procedure source see Manual upload below.
Each build is tracked independently and has a clearly defined lifecycle.
Build Lifecycle
Every build progresses through a set of well-defined states:
- Pending — the build has been created and is waiting to be processed by our server.
- Building — the source code is being compiled. The build logs will be visible after the build finishes.
- Success — the build completed successfully, and the procedure is ready to be executed.
- Error — the build failed due to compilation or validation errors.
- Cancel — the build has been cancelled.
Only builds that reach the Success state can be used by the Executor.
Builds can fail for multiple reasons. Review the build logs to see if the error is related to the source code or something else.
To avoid redundant work, builds for a git commit hash that has already been successfully built may be automatically canceled. In that case, the previously successful build is reused.
Manual upload
Each procedure source can also be used without providing source code by uploading build WASM artifacts directly to Zela.
We expect a WASM Component that fulfills this WIT world. For Rust we provide the zela-std crate, then build for the wasm32-wasip2 target and cdylib crate type. Check out our zela-demo repository to help you get started.
Once you have built your WASM artifact, you can upload it to Zela using the Zela dashboard by editing your procedure or through our API:
curl -f \
-H "authorization: Bearer $ZELA_JWT" -H 'content-type: application/wasm' \
--data-binary '@target/wasm32-wasip2/release/hello_world.wasm' \
"https://core.zela.io/procedures/$ZELA_PROCEDURE/wasm?project=$ZELA_PROJECT&file_name=hello_world.wasm"
To obtain the ZELA_JWT use one of your project keys as described in the Execution section.
For further inspiration take a look at our demo GitHub Actions workflow file which implements manual upload.
After a Successful Build
Once a build completes successfully:
- the procedure becomes available for execution,
- the Executor can start processing requests using this build,
- build logs and metadata remain accessible for inspection.
From this point, the procedure can be executed and monitored through the platform.
Execution & Debugging
This section describes how procedures are executed on zela.io and how common issues can be investigated and resolved.
Executing a Procedure
A procedure becomes available for execution once it has been built successfully.
Procedures are executed by sending a JSON-RPC HTTP request to the executor URL - https://executor.zela.io.
The first step of this process is obtaining a JWT representing access to your project. The JWTs are short-lived but can be generated asynchronously and used when calling the RPC.
To obtain the JWT perform a client_credentials OAuth2 flow against our Identity Provider with one of your Project keys. You can generate and inspect a project key in the Dashboard.
curl --header 'Authorization: Basic base64($key_client_id:$key_secret)' --data 'grant_type=client%5Fcredentials' --data 'scope=zela%2Dexecutor%3Acall' 'https://auth.zela.io/realms/zela/protocol/openid-connect/token'
Once you have obtained the access_token from the response use it as Bearer authentication for your JSON-RPC calls as follows:
curl --header 'authorization: Bearer $jwt' --header 'Content-Type: application/json' --data $'{ "jsonrpc": "2.0", "id": 1, "method": "zela.zela-demo#32902637cc96f8d95ee436d1e9ea30e49abd06b0", "params": { "first_number": 123, "second_number": 456 }}' 'https://executor.zela.io'
This would execute procedure zela-demo build commit hash 32902637cc96f8d95ee436d1e9ea30e49abd06b0 from the project tied to the JWT. If the Executor does not have the procedure cached it will take a few seconds to load it into memory. Afterwards it will use the cached procedure and apply your configured concurrency limits (as set before in the Onboarding or Dashboard).
- Each procedure has configurable concurrency limits that control how many requests can run in parallel. You can adjust these limits in the Onboarding workflorw and Dashboard.
Using Logs for Debugging
Logs are the primary source for debugging issues on zela.io.
Typical use cases include:
- reviewing build logs to identify compilation or validation errors,
- inspecting execution logs to diagnose runtime failures.
To emit logs from your procedures use the log crate integration enabled in our zela-std crate. Note that the default maximum log level is set to INFO, but can be configured in your procedure at compile time.
Common Debugging Steps
When a procedure does not behave as expected, the following steps are recommended:
- Ensure the source configuration (repository, branch, procedure name) is correct.
- Verify that the latest build completed successfully.
- Review build logs for errors or warnings.
- Inspect execution logs for runtime failures.
- Confirm that input parameters are valid and correctly formatted.
-
If you are using solana-client RpcClient::send please note that the client requires the parameters to be an array. If you wish to use the RpcClient to also interact with zela.io you can wrap your input parameters in an array:
impl CustomProcedure for YourProcedure { type Params = [YourParams; 1]; // ... async fn run(params: Self::Params) -> Result<Self::SuccessData, RpcError<Self::ErrorData>> { let [params] = params; // ... your code } }
-
Support
If you have any further questions or need help with anything don’t hesitate to contact us at support@zela.io