Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

How It Compares

datalogic-rs is a JSONLogic engine: rules are JSON data, evaluated by one Rust core that ships as eight packages (Rust, Node.js, browser WASM, Python, Go, JVM, .NET and PHP). This page compares it with the alternatives people most often weigh it against. For raw numbers and methodology, see Performance and the benchmark matrix.

Dimensiondatalogic-rsjson-logic-jsjson-logic-enginejsonlogic-rsGoRules ZENCEL
FormatJSONLogic (JSON data)JSONLogic (defines the standard)JSONLogic supersetJSONLogicProprietary JDM + Zen expression languageCEL expression grammar (not JSON)
LanguagesOne core, official bindings for Rust, Node, WASM, Python, Go, Java, .NET, PHPJS core; other languages are separate community portsJS/TS onlyRust (single crate, Python/WASM wrappers exist but stale)Rust core with several bindingsGo/Java mature, others varying
Standard compliancePasses the official JSONLogic test suite, plus opt-in extensionsThe reference implementationSuperset with minor deviationsPasses core suiteNot JSONLogicOwn spec
SandboxingNo eval, no I/O, core forbids unsafe codeNo evalNo evalNo evalFunction nodes execute JavaScript (QuickJS)Non-Turing-complete, strong formal story
ToolingReact visual editor, step-through trace debugger, online playground, rule checker (check)Play pageNone officialNone officialJDM editor + commercial BRMSCommunity playgrounds
ExtensibilityCustom operators per host languageCustom ops in JSCustom ops (incl. async) in JSLimitedCustom nodesExtension functions per environment

jsonlogic-rs on crates.io is bestowinc/json-logic-rs, a different project despite the near-identical name. This crate is datalogic-rs. The section below compares the two.

One engine vs. N ports

JSONLogic promises portability: rules are plain JSON, so any language can evaluate them. In practice json-logic-js is the JavaScript reference, and each other language relies on an independent reimplementation: community ports for Python, PHP, Go, Ruby, Java and more, each with its own maintainer, release cadence and bugs. The ports drift. Truthiness edge cases, type coercion, null handling and error behavior diverge one patch release at a time, and a rule that passes tests in your Node service can evaluate differently in your Python batch job.

datalogic-rs compiles one Rust core into every runtime. The Node addon, the WASM package, the Python wheel, and the Go, Java, .NET and PHP bindings all embed the same engine, and none of them reimplements an operator. Two checks keep the languages in step:

  • The same 2,128-case conformance battery (66 suites) runs against the core in CI, and again through the Node, WASM, Python and Go bindings and the C ABI that the JVM, .NET and PHP bindings load. A shared scenario suite (bindings/scenarios/api.json) checks the API surface in all eight.
  • The flagd fractional operator is byte-compatible with the canonical Go evaluator’s MurmurHash3 bucketing, so a hash-based percentage rollout puts the same user in the same bucket in every language.

When to choose which

datalogic-rs fits when your rules should be data: stored in a database column, diffed in review, generated by a UI, and evaluated with identical semantics on the client and every backend service. What sets it apart is one engine shared across eight runtimes and an official visual debugger for the standard. Each alternative below is the better pick for the case it describes.

json-logic-js

The reference implementation, and the project that defines the JSONLogic standard. datalogic-rs passes the same official test suite, so existing json-logic-js rules run unchanged.

Choose it when: you only need JavaScript, you want the smallest and longest-used dependency, and the reference engine’s speed is enough at your rule volume. As the standard’s source of truth, it is the default choice for a JS-only stack.

Choose datalogic-rs when: the same rules must also run outside JavaScript, evaluation is hot enough to show up in profiles (the native engine measures about 84x faster across the shared benchmark suites), or you want the visual debugger and playground.

Migrating is close to a package swap; the full mapping is in Coming from json-logic-js.

json-logic-engine

A fast, actively maintained JavaScript engine: its compiled mode is the only non-Rust subject within the same order of magnitude as datalogic-rs in the benchmark matrix.

Choose it when: your stack is JS/TS end to end and you want JS-native ergonomics, above all async custom operators, which datalogic-rs’s synchronous custom-operator callbacks do not offer.

Choose datalogic-rs when: you need one core across many languages, native (non-JS) bindings, closer adherence to the reference semantics, or the visual tooling. Rules that stay inside the shared JSONLogic standard carry over unchanged.

jsonlogic-rs (bestowinc)

The similarly named crate on crates.io, and the comparison people search for most. jsonlogic-rs is a single-crate Rust implementation of core JSONLogic with an apply(&Value, &Value) API: there is no compile step, so every call re-walks the rule JSON. Python and WASM wrappers exist in the same repository but have not seen recent releases. It is a small dependency for occasional evaluation of standard rules.

Choose it when: you want a minimal one-function crate, your rules stick to the core standard, and evaluations are infrequent enough that per-call rule walking does not matter.

Choose datalogic-rs when: evaluation is hot (compile-once evaluation measures about 28x faster geomean on the shared suites), you need the extended operators (datetime, string, try/throw, flagd), custom operators, tracing, or any of the non-Rust bindings. Both engines speak JSONLogic, so rules carry over unchanged; switching is confined to the Rust call sites, and the quick start shows the equivalent one-liner.

GoRules ZEN

A business-rules platform built around decision tables and graphs (a proprietary JDM format), with a commercial editor. It solves a bigger problem than expression evaluation.

Choose it when: you want a full BRMS abstraction for business users: decision tables, graph orchestration, and a polished commercial editing experience on top of the engine.

Choose datalogic-rs when: you want a lighter embedding around an open standard, or a stricter sandbox: ZEN’s function nodes run JavaScript (QuickJS), while datalogic-rs runs no code a rule supplies.

CEL

Common Expression Language is the standard safe expression language in the Kubernetes and Envoy ecosystems, with a non-Turing-complete guarantee and a formal spec.

Choose it when: you want an expression grammar (not JSON) and its ecosystem integrations, or you already live in a CEL-native environment such as Kubernetes admission control.

Choose datalogic-rs when: rules should be plain JSON: storable, diffable, and UI-generatable with no grammar or parser to maintain, plus an official visual editor for the people who write the rules.

The numbers

Geomean execution time across 51 benchmark suites (Apple M2 Pro; median of 3 samples; ratios are pairwise shared-suite geomeans; methodology in the benchmark matrix).

datalogic-rs (native Rust)              | 10.3 ns  (■) 1x
json-logic-engine (JS, compiled)        | 63.3 ns  (■■■■■■) 7.0x
json-logic-engine (JS, interpreted)     | 234.8 ns (■■■■■■■■■■■■■■■■■■■■■■■) 25.8x
jsonlogic-rs (bestowinc Rust engine)    | 264.2 ns (■■■■■■■■■■■■■■■■■■■■■■■■■■) 28.1x
json-logic-js (Reference JS library)    | 465.1 ns (■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■) 83.6x

The WASM build under Node measures 900.5 ns (88x native), so on Node servers use the native binding; the WASM package is for browsers and edge runtimes.

Proof: the same rule everywhere

One rule, one datum, eight runtimes:

{
  "and": [
    {">=": [{"var": "age"}, 18]},
    {"==": [{"var": "status"}, "active"]}
  ]
}

With data {"age": 25, "status": "active"}, every binding returns true:

RuntimeOne-line call
Rustdatalogic_rs::eval_str(rule, data)?
Node.jsapply(rule, data)
Browser (WASM)new Engine().evalStr(rule, data)
Pythonapply(rule, data)
Godatalogic.Apply(rule, data)
Javaengine.apply(rule, data)
C#engine.Apply(rule, data)
PHP$engine->apply($rule, $data)

All eight calls run the same compiled core. Try the rule live in the playground (live Studio), then pick your language in Installation.

See Also