Skip to content

Bonsai-js vs JSONata: Which Should You Use for Data Transformation and Expression Evaluation?

I needed to evaluate dynamic expressions in a JavaScript project and kept finding two libraries mentioned: bonsai-js and JSONata. They both seemed to handle expressions, but which one should I pick?

After trying both and hitting some walls, I realized they serve different purposes despite the overlap.

The Problem

I was building a feature that needed to evaluate user-defined business rules. My first instinct was to reach for JSONata since I’d used it before for data transformation. But the syntax felt wrong for what I was doing. Expressions like score > 80 and yearsActive >= 2 required learning JSONata’s DSL with its and/or keywords instead of JavaScript’s familiar &&/||.

Then I found bonsai-js, which promised JavaScript-familiar syntax and 30M ops/sec performance. But wait - could I use it for data transformation too?

My Environment

  • Node.js 20.x
  • Need for safe expression evaluation (no eval())
  • Mix of use cases: business rules evaluation and occasional data transformation
  • Team familiar with JavaScript syntax

What I Found

I tried both libraries on similar tasks and discovered they excel in different areas.

JSONata shines for data querying and reshaping:

jsonata-demo.js
const jsonata = require('jsonata');
const data = {
orders: [
{ id: 1, items: [{ price: 10, qty: 2 }, { price: 5, qty: 3 }] },
{ id: 2, items: [{ price: 20, qty: 1 }] }
]
};
// JSONata: Sum all order totals - elegant path syntax
const expression = jsonata('$sum(orders.items.(price * qty))');
const total = expression.evaluate(data); // 45
// JSONata: Reshape to order summary
const reshapeExpr = jsonata(`
orders.{
"orderId": id,
"itemCount": $count(items),
"total": $sum(items.(price * qty))
}
`);
const summary = reshapeExpr.evaluate(data);
// [{ orderId: 1, itemCount: 2, total: 35 }, { orderId: 2, itemCount: 1, total: 20 }]

Bonsai-js excels at business rule evaluation:

bonsai-demo.js
import { evaluate, compile } from 'bonsai';
// User-defined pricing rule - JS syntax I already know
const pricingRule = 'basePrice * (1 + taxRate) - discount > 0';
const context = {
basePrice: 100,
taxRate: 0.08,
discount: 10
};
const isValid = evaluate(pricingRule, context); // true
// Admin-defined filter condition
const filterCondition = 'status === "active" && age >= 18 && verified';
const user = { status: 'active', age: 25, verified: true };
const passesFilter = evaluate(filterCondition, user); // true
// Formula field calculation with ternary operators
const formula = 'hoursWorked * hourlyRate + (hoursWorked > 40 ? (hoursWorked - 40) * hourlyRate * 0.5 : 0)';
const timesheet = { hoursWorked: 45, hourlyRate: 20 };
const pay = evaluate(formula, timesheet); // 950 (40*20 + 5*20*1.5)

The syntax difference became clearer when I compared the same task:

syntax-comparison.js
// Task: Check if user qualifies for premium tier
const user = { score: 85, yearsActive: 3, referrals: 5 };
// JSONata syntax - AND/OR keywords, different operators
const jsonata = require('jsonata');
const jsonataRule = jsonata('score > 80 and yearsActive >= 2 and referrals >= 3');
// Bonsai syntax - JS-familiar && and ||
import { evaluate } from 'bonsai';
const bonsaiRule = 'score > 80 && yearsActive >= 2 && referrals >= 3';
const qualifies = evaluate(bonsaiRule, user); // true

The Solution

I ended up using both in my project, but for different purposes.

Use JSONata when:

  • Navigating complex nested JSON structures (like API responses)
  • Reshaping data from one format to another
  • Performing aggregations, filtering, and sorting on JSON data
  • You need XPath-like power for JSON documents
  • Building data transformation pipelines

Use bonsai-js when:

  • Building formula fields and computed columns
  • Implementing admin-defined business rules engines
  • Creating user-facing filter/condition builders
  • Adding template logic without a template engine
  • Evaluating product configuration expressions
  • You need 30M ops/sec performance for high-frequency evaluation
  • You want zero dependencies and a small bundle size
  • Your team already knows JavaScript syntax

For high-frequency evaluation scenarios, bonsai’s compiled expressions made a huge difference:

performance-comparison.js
// Bonsai: High-frequency evaluation (30M ops/sec)
import { compile } from 'bonsai';
const compiledRule = compile('value > threshold');
for (let i = 0; i < 1000000; i++) {
compiledRule({ value: i, threshold: 500000 }); // Extremely fast
}
// JSONata: One-time data transformation
const transformData = jsonata(`
$map(data, function($item) {
{
"name": $item.firstName & ' ' & $item.lastName,
"email": $item.email,
"status": $item.active ? 'active' : 'inactive'
}
})
`);
const transformed = transformData.evaluate({ data: usersArray });

Why This Matters

Using JSONata for business rule evaluation means learning unfamiliar syntax (& for concat, and/or instead of &&/||, $sum() for aggregation). Using bonsai for complex JSON reshaping means writing more verbose expressions than JSONata’s elegant path syntax.

The wrong choice increases cognitive load for your team and can impact performance if you’re doing high-frequency evaluations.

Summary

In this post, I compared bonsai-js and JSONata for expression evaluation and data transformation in JavaScript. The key point is: use JSONata for data querying and reshaping (think XPath for JSON), use bonsai-js for business rules and expression evaluation with JavaScript-familiar syntax. They can coexist in the same project - I use each for its strengths.

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