Skip to content

bonsai-js vs Jexl: Which JavaScript Expression Evaluator Should You Choose?

I needed a JavaScript expression evaluator for a business rules engine. The expressions would be evaluated frequently in production, so performance mattered. I also wanted modern JavaScript syntax - optional chaining, nullish coalescing, template literals - without the complexity of sandboxed JS environments like quickjs-wasm.

The Problem

My application needed to evaluate user-defined expressions safely. Business rules, template systems, conditional logic - all requiring expression evaluation. I looked at Jexl first since it’s established and widely used.

But I hit a wall. Jexl doesn’t support modern JavaScript syntax. No optional chaining (?.), no nullish coalescing (??), no template literals. I found myself writing verbose fallback expressions:

verbose-fallback.js
// What I wanted to write
user?.profile?.name ?? "Anonymous"
// What I had to write with Jexl
user.profile && user.profile.name ? user.profile.name : "Anonymous"

I even considered extending Jexl’s language to support these features. Then I discovered bonsai-js.

What I Found

bonsai-js is a newer expression evaluator built with modern JavaScript syntax in mind. Here’s what caught my attention:

Modern syntax support out of the box:

bonsai-modern-syntax.js
import { evaluate } from 'bonsai';
const context = { user: { profile: { name: 'Alice' } } };
// Optional chaining
const name = await evaluate('user?.profile?.name', context);
// Result: 'Alice'
// Nullish coalescing
const displayName = await evaluate('user?.profile?.nickname ?? "Guest"', context);
// Result: 'Guest'
// Template literals
const greeting = await evaluate('`Hello, ${user.profile.name}!`', context);
// Result: 'Hello, Alice!'
// Spread and lambdas
const doubled = await evaluate('[1, 2, 3].map(x => x * 2)', {});
// Result: [2, 4, 6]

Performance that matters:

bonsai-performance.js
import { compile } from 'bonsai';
const compiled = compile('user?.permissions?.includes("admin") ?? false');
const context = { user: { permissions: ['admin', 'user'] } };
// 30M ops/sec on cached expressions
for (let i = 0; i < 1_000_000; i++) {
compiled(context);
}

The 30M ops/sec comes from a Pratt parser with compiler optimizations - constant folding, dead branch elimination - and LRU caching for repeated expressions.

Zero dependencies:

bundle-comparison.txt
bonsai: 0 dependencies
jexl: multiple dependencies

Smaller bundle, fewer security concerns, simpler dependency tree.

Jexl’s Strengths

Jexl isn’t without merit. It has a mature ecosystem with real tooling:

  • Syntax highlighting extensions for editors
  • Linting support
  • Custom transformer system for domain-specific operations
jexl-transformers.js
import Jexl from 'jexl';
// Jexl's transformer system
Jexl.addTransform('upper', val => val.toUpperCase());
const result = await Jexl.eval('user.name|upper', context);
// Result: 'ALICE'

If you’ve invested in Jexl-specific tooling, the ecosystem advantage is real.

Feature Comparison

Featurebonsai-jsJexl
Optional chaining (?.)YesNo
Nullish coalescing (??)YesNo
Template literalsYesNo
Spread operatorYesNo
Lambda expressionsYesLimited
Zero dependenciesYesNo
Performance (cached)30M ops/secLower
TypeScript built-inYesVia @types
Editor extensionsComingYes
Custom transformersNoYes
MaturityNewEstablished

The Decision

For my new project, I chose bonsai-js. Here’s why:

  1. Modern syntax reduces cognitive load - I write expressions the same way I write JavaScript
  2. Performance isn’t a bottleneck - 30M ops/sec means expression evaluation won’t slow down my app
  3. Zero dependencies - Cleaner bundle, fewer security concerns
  4. Built-in TypeScript - No separate @types package needed

For validation and tooling, bonsai’s validate() function extracts references from expressions:

bonsai-validation.js
import { validate } from 'bonsai';
const result = validate('user.profile.age > 18');
console.log(result.references);
// ['user', 'profile', 'age']

This enables editor integrations similar to what Jexl offers.

When to Stick with Jexl

If you have an existing Jexl codebase, consider:

  • Do you use custom transformers heavily?
  • Have you built editor extensions around Jexl?
  • Is your team familiar with Jexl’s syntax?

If yes to any of these, migration cost may outweigh immediate benefits. But if you’re hitting syntax limitations frequently, the switch could be worth it.

Common Mistakes to Avoid

  1. Choosing based solely on npm downloads - Jexl has more downloads, but bonsai may be better for your use case
  2. Not considering syntax migration cost - Map your expressions before switching
  3. Assuming quickjs-wasm is the only safe option - Both libraries provide sandboxed evaluation
  4. Overlooking performance impact - Expression evaluation can become a bottleneck in hot paths

Summary

In this post, I compared bonsai-js and Jexl for JavaScript expression evaluation. The key points:

  • bonsai-js for new projects: modern syntax, 30M ops/sec performance, zero dependencies
  • Jexl for existing codebases: mature tooling, custom transformers, established ecosystem
  • Both provide safe sandboxed evaluation without quickjs-wasm complexity

For my business rules engine, bonsai-js won because modern syntax and performance mattered more than mature tooling. Your mileage may vary.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments