Open-source project
schibsted/jslt avatar
schibsted/jslt

JSLT: a JSON query and transformation language built for Java services

JSON query and transformation language

702 stars130 forksJavaApache-2.0

At a glance

What is it?
JSLT is a small expression language for JSON, designed to sit inside a Java service rather than at a shell prompt, with a Jackson-based library, a command line runner, extension functions and a stated production use of about nine billion transforms a day at Schibsted.
Who is it for?
JSLT fits a Java team that wants to let users or operators write their own JSON filters and mappings without shipping a new jar for every request, since the language is small enough to embed in a service and the transform is just a string.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 13 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Three uses of one language: query, filter, transform

JSLT is described as a complete query and transformation language for JSON, with the design inspired by jq, XPath and XQuery. The project lists three ways it can be used. As a query language it extracts values from JSON with an expression like .foo.bar[0]. As a filter or check language it tests JSON objects, for instance starts-with(.foo.bar[0], "http://"). As a transformation language it converts between JSON formats. That third use is where the language is really designed to live, and the example transform in the project overview is a good illustration, because it is not a single expression but a whole object constructor with a nested object and a function call on a parsed date.

code
{
    "time": round(parse-time(.published, "yyyy-MM-dd'T'HH:mm:ssX") * 1000),
    "device_manufacturer": .device.manufacturer,
    "device_model": .device.model,
    "language": .device.acceptLanguage,
    "os_name": .device.osType,
    "os_version": .device.osVersion,
    "platform": .device.platformType,
    "user_properties": {
        "is_logged_in" : boolean(.actor."spt:userId")
    }
}

The language is not finished in the sense that functions may be added, but the project states the language as it stands is not likely to change, which is the property that matters for a language you might let other people write.

The quick reference fits on one screen

The syntax summary in the overview is short enough to read in a minute, which is a good sign for a language meant to be written by people who are not language designers. The context node is written as a dot. Keys are read with a dot and a name, and a quoted name handles keys that are not plain identifiers, as the transform example shows with .actor."spt:userId". Arrays are indexed with square brackets, and ranges with a colon, so .[0] and .[0 : 2] both work. Beyond access there are the usual control constructs: if with an else branch, let for variables referenced with a dollar sign, for expressions over arrays written in bracket form and over objects written with a key and a colon, and def for declaring a function. A line comment runs to the end of the line, and object construction is the curly brace form. Arithmetic and comparison operators are there as well, along with boolean operators written in words.

Embedding it in a Java service takes three lines

The library entry point is small, which is the whole point of putting a language inside a JVM. You compile a transform string into an Expression and apply it to a JsonNode.

code
import com.schibsted.spt.data.jslt.Parser;
import com.schibsted.spt.data.jslt.Expression;

JsonNode input = ...;
Expression jslt = Parser.compileString(transform);
JsonNode output = jslt.apply(input);

Because the input and output are Jackson types, the language sits inside an existing Jackson-based service without an adapter, and a transform can be stored in a database, fetched from configuration or accepted from an API and compiled on demand. The project points at the javadoc for more alternatives, and the API introduction document in the docs directory for the wider picture. At runtime the library depends on Jackson and nothing else, which is worth noting for anyone counting dependencies in a service.

One dependency, and the Jackson 2 to Jackson 3 handover

Adding JSLT to a project is a single Maven dependency, and the coordinates are the com.schibsted.spt.data group.

code
<dependency>
  <groupId>com.schibsted.spt.data</groupId>
  <artifactId>jslt</artifactId>
  <version>0.1.15</version>
</dependency>

The Jackson situation is the one detail to plan around. The project states that versions up to and including 0.1.15 depend on Jackson 2, while 0.1.16, which is not yet released, and higher depend on Jackson 3. Serious bugs in 0.1.15 will be fixed, but no new features will be developed in the Jackson 2 series. So the current artifact is a maintenance release rather than the place to expect new functions, and the migration to Jackson 3 is a scheduled event rather than a surprise. The project uses Java 11, which sets the floor for both the library and anyone embedding it.

Running transforms from the command line

There is a command line interface for the cases where you want to try a transform without writing Java. The build produces a shadow jar, and the runner is a class on that jar's classpath.

code
java -cp build/libs/*.jar com.schibsted.spt.data.jslt.cli.JSLT transform.jslt input.json

The transform is a file and the input is a file, and the result is written to standard output, so it pipes into whatever you use next. The build itself is Gradle: ./gradlew clean shadowJar produces the fat jar, ./gradlew jar produces a plain jar, and ./gradlew check runs the tests. One oddity worth knowing is the pom.xml at the repository root. The project says Maven is not used for building JSLT and the file is not intended to work, and it is there only so that GitHub dependency tracking works. If you find a pom.xml in the repository and try to build with Maven, that is why nothing happens.

Extending the function library from Java

You can implement your own functions and add them to the language, and the project has a dedicated tutorial for it. This is the part that separates JSLT from a fixed expression evaluator. A domain with its own vocabulary, say a telecom payload or a payments event, can expose those operations as JSLT functions and then let the people who write the transformations use them, rather than maintaining a bespoke Java class per transformation request. The separation is also visible in the source layout, with a core/ directory for the language itself, a support/ directory, a playground/ directory for running the online demo yourself, and an ideas/ directory that is likely where design notes live, next to the language-design.txt file at the root. The examples directory ships two sample transforms, flatten.jslt and queens.jslt, alongside its own README.

Production use at Schibsted, and what the status section promises

The status section of the overview is unusually informative. The language design is not finished, so features may be added, but the language as it stands is not likely to change. The entire language is implemented, along with all of the function library, though functions may still be added. And the project states the language has been used in production at Schibsted since January 2018, performing about nine billion transforms per day, and many times more queries. That is a scale worth pausing on, because it means the library is not a demonstration of a research idea but a component running in a busy pipeline, which is also why the Jackson 2 series is being frozen rather than extended. The last push to the repository was on 2026-10-10, and the recent releases are 0.1.15 on 2026-09-11, with 0.1.14 from 2022-11-09 before it.

Where JSLT fits, and where it does not

The obvious comparison is jq, and the difference in approach is the point. jq is a command line tool you pipe JSON through, written in C, with a large user base of people who live in a shell. JSLT is a JVM library for a language that lives inside a service, where a transform is a value you can store, validate and compile at runtime, and where the surrounding data model is Jackson rather than text on standard input. The ecosystem reflects that: there is a demo playground and a tutorial, a Visual Studio syntax highlighter and an IntelliJ plugin, an Apache Camel component, integration as a processor in Apache NiFi, a JavaScript port with its own playground, and a paper on how Schibsted uses it. The boundary of the tool is the same in both directions. If your transforms are written by developers who live in a terminal, jq is the more natural home, and if they are written by people configuring a deployed service, JSLT fits better. The licence is Apache 2.0, held by Schibsted Marketplaces Products and Technology AS.

Editorial conclusion

JSLT fits a Java team that wants to let users or operators write their own JSON filters and mappings without shipping a new jar for every request, since the language is small enough to embed in a service and the transform is just a string. It does not fit a project on Jackson 3 that wants a maintained library today, because the Jackson 3 line is version 0.1.16 and not yet released, so the current 0.1.15 still depends on Jackson 2 and no new features will be developed in that series. It also does not fit someone who expects a shell tool like jq, since the runner is a Java class rather than a native binary. Before you adopt it, read the tutorial and the function documentation rather than judging from the quick reference, plan the move to the Jackson 3 based release, and if you need domain specific functions, look at the extension function tutorial before assuming the standard library covers your case.

Frequently asked questions

How do I use JSLT in a Java project?

Add the com.schibsted.spt.data:jslt dependency, then compile a transform string with Parser.compileString and apply it to a JsonNode with Expression.apply. The library depends on Jackson and nothing else at runtime, and the project uses Java 11.

What does JSLT depend on at runtime?

Jackson and nothing else. Versions up to and including 0.1.15 depend on Jackson 2, while 0.1.16, not yet released, and higher depend on Jackson 3. Serious bugs in 0.1.15 will be fixed, but no new features will be developed in the Jackson 2 series.

Can I run a JSLT transform from the command line?

Yes. Build the fat jar with ./gradlew clean shadowJar, then run the JSLT class with a transform file and an input file, for example java -cp build/libs/*.jar com.schibsted.spt.data.jslt.cli.JSLT transform.jslt input.json. The result is written to standard out.

Can I add my own functions to JSLT?

You can implement your own functions and add them to the language, and the project publishes an extension function tutorial covering the approach. The standard library is described as complete, though further functions may be added over time.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. README
  4. Releases
  5. schibsted/jslt on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/schibsted-jslt.svg)](https://hysenlabs.com/projects/schibsted-jslt)

Was this useful?