· 5 min read ·

One Day, One Port, Five Hundred Thousand Dollars: What the JSONata Rewrite Reveals About AI-Assisted Migration

Source: simonwillison

There is a category of engineering work that almost never gets done: the correct rewrite. You have a dependency that is technically wrong for your stack, expensive to run, or increasingly painful to maintain, but the effort to replace it is large enough that it keeps getting deprioritized. JSONata has quietly sat in that category for a lot of teams.

Simon Willison linked to a post from the team at Vine describing how they rewrote the JSONata runtime using AI assistance in a single day, and the result was $500,000 per year in savings. That number is striking enough to stop and think about. But to understand why this particular rewrite matters, you need to understand what JSONata actually is and why it ends up embedded in so many systems.

What JSONata Is and Why It Is Everywhere

JSONata is a query and transformation language for JSON, created by Andrew Coleman at IBM and open-sourced around 2016. The reference implementation is in JavaScript, MIT licensed. It was designed to fill the gap that XPath/XSLT filled for XML: a way to both extract data from and transform JSON documents using a concise expression language.

The syntax borrows from JavaScript but adds its own semantics. Path navigation works like Account.Order.Product.Price, wildcards cover Account.*.Price, and recursive descent handles Account.**.Price. You get predicate filters, aggregation functions, higher-order functions, variable binding, and lambda expressions. It looks like this:

$sum(Account.Order.Product.(Price * Quantity))

That expression sums all products of Price times Quantity across all orders across all accounts. In JavaScript you would write a nested reduce with null checks. JSONata makes it a single line.

What made JSONata take off was its adoption in integration tooling. Node-RED, IBM’s open-source flow-based programming tool that now has millions of deployments, uses JSONata as its expression language. IBM App Connect uses it. A number of low-code platforms use it. When you are building integration middleware that needs to transform data between systems, JSONata gives you a language that non-programmers can write and that compiles to something deterministic and auditable.

The catch is the runtime. The JavaScript implementation was built as a reference interpreter. It is not fast. It allocates aggressively, builds an AST on every evaluation unless you explicitly pre-compile, and its async evaluation mode (designed for safe sandboxed execution with timeouts) carries significant overhead. For any system handling high throughput, the JSONata runtime becomes a bottleneck and a cost center.

The Port Problem

Rewiring a runtime like JSONata into another language is not a small project. You are not just translating syntax; you are reimplementing semantics. JSONata has a specification, but like most query languages, the specification is informal and the behavior is defined by the test suite. Edge cases in string handling, type coercion, sequence semantics, the behavior of undefined propagation through path expressions: these are subtle, and getting them right requires either deep familiarity with the original implementation or extensive testing against the reference.

Historically, this work would take weeks at minimum, probably months for a production-quality port with full spec coverage. That cost-benefit rarely penciled out unless you were a platform vendor with JSONata embedded at the core of your product.

The Vine team’s post changes that calculation. They used an LLM, working through the JavaScript source and test suite, to produce a port in a single day. The $500K annual savings presumably reflects the compute costs of running the JavaScript runtime at scale, licensing, or some combination of infrastructure and operational cost that the new implementation eliminates.

What AI-Assisted Porting Actually Looks Like

The mechanics of this kind of work have become a recognizable pattern. You feed the LLM the source implementation in chunks, ask it to produce equivalent code in the target language, and then run the existing test suite against the output. The model handles the mechanical translation; you handle the cases where it halts or gets semantics wrong.

JSONata’s JavaScript implementation is around 5,000 lines in the core evaluator, plus several thousand more in the standard library of functions. That is within the range where a capable LLM can hold enough context to make coherent translation decisions. The real work is validation: JSONata has hundreds of test cases organized by feature area, covering normal paths and edge cases.

The interesting constraint in any language port of a dynamic-language runtime is type handling. JSONata is dynamically typed, JavaScript is dynamically typed, and the semantics of operations on mixed types are part of the language. If you are porting to Rust or Go, you have to decide how to represent JSONata’s value type. A common approach is a recursive enum or tagged union:

enum Value {
    Null,
    Bool(bool),
    Number(f64),
    String(String),
    Array(Vec<Value>),
    Object(IndexMap<String, Value>),
    Undefined,
}

JSONata’s undefined propagation rules then become pattern matching. The path expression semantics, where navigating into a missing key returns undefined rather than an error, have to be built into every evaluation step. An LLM translating from JavaScript will carry these semantics over by pattern, but you need your test suite to catch the places where the translation drifts.

The Economics of One Day

The $500K figure is worth examining. At AWS Lambda pricing or standard container compute rates, you need to be handling a substantial volume of JSONata evaluations to run up half a million dollars per year. That suggests Vine is running JSONata at the core of a data pipeline or integration layer processing significant throughput, not as a peripheral utility.

This is the use case where the JavaScript runtime’s performance characteristics hurt most. The reference implementation was built to be correct and portable, not fast. Running it in a Node.js process at high concurrency involves V8’s overhead, the GC pauses that come with the reference implementation’s allocation patterns, and the async evaluation path’s cost if you are using safe mode.

A port to a compiled language with a more efficient value representation can realistically achieve 10-20x throughput for common expressions. At the scale implied by $500K/year in compute, that margin is significant. The fact that AI brought the porting cost down to a single engineering day means the payback period on the project was, in the most literal sense, immediate.

What This Changes

The Vine story is a clean example of something worth tracking: AI assistance does not just speed up greenfield code. It changes the threshold for correctness-preserving rewrites of mature, tested codebases. A language port of something like JSONata used to be a project you staffed and scoped. It is now potentially a day’s work with an LLM and a good test suite.

The test suite is the key constraint. JSONata’s test coverage is what made this feasible. If you wanted to do the same thing with an underdocumented internal library, you would spend more time writing the tests than doing the translation. The lesson for teams with expensive dependencies they have been tolerating is not just “AI can do the port.” It is “invest in test coverage so that when the moment comes, you can validate the port.”

For anyone running JSONata at scale, the jsonata-js repository and its test suite are the starting point. For anyone building new systems that need JSON transformation, this rewrite is a reminder that the choice of runtime language is not permanent, and that the cost of changing it has dropped substantially.

Was this interesting?