Skip to main content
The ZEN Engine is written in Rust, giving you direct access to the core engine with zero FFI overhead.

Installation

Add to your Cargo.toml:

Basic usage

Loader

The loader pattern enables dynamic decision loading from any source. ZEN Engine provides several built-in loaders.

FilesystemLoader

Load decisions from a directory:

MemoryLoader

Store decisions in memory:

Closure loader

Define custom loading logic with an async callback:

Custom loader

Implement the DecisionLoader trait for full control:

Cloud storage loaders

For production-ready cloud storage loaders (AWS S3, Azure Blob Storage, Google Cloud Storage) with zip support, see the reference implementation:

GoRules Agent

Reference implementation with cloud storage loaders for S3, Azure, and GCS

Pre-compilation

Pre-compile decisions for improved evaluation performance:
Compilation parses and optimizes the decision graph ahead of time, reducing overhead during evaluation. This is especially beneficial when the same decision is evaluated many times.

Error handling

Tracing

Enable tracing to inspect decision execution:

Expression utilities

The zen-expression crate provides expression evaluation outside of decisions:

High performance with Isolate

For repeated evaluations, use Isolate to reuse allocated memory:

Design notes

Single-threaded expression engine

The expression engine is single-threaded by design for maximum performance. This avoids synchronization overhead and enables optimizations like memory reuse in Isolate.

Thread-pinned futures

Although evaluate is async, the returned Future is !Send — it must complete on the same thread where it was started. This is intentional: sending data across threads would be costly in this scenario, and pinning enables significant performance gains. However, this can be awkward with async runtimes that expect Send futures. For multi-threaded workloads, use LocalPoolHandle from tokio-util to spawn pinned tasks:
Usage:

Best practices

Use FilesystemLoader with keep_in_memory: true. This caches parsed decisions in memory for optimal performance. Initialize the engine once. Create a single DecisionEngine instance at application startup and reuse it for all evaluations. Use Isolate for repeated expression evaluation. It reuses allocated memory, drastically improving throughput.