DevToolLab

Free, fast, and powerful online tools for developers. Convert, format, and transform your data with ease.

© 2026 DevToolLab. All rights reserved.

Quick Links

ToolsBlogAbout
ContactFAQSupportTermsPrivacy
Upgrade to Pro (Ad-free)

Connect With Us

X

Have questions? Contact us

  1. Home
  2. /
  3. Blog
  4. /
  5. What Is JSONata? Learn How to Query JSON Like a Pro
Back to all posts
Tutorial
6 min read

What Is JSONata? Learn How to Query JSON Like a Pro

DevToolLab Team

DevToolLab Team

April 25, 2025 (Updated: March 10, 2026)

What Is JSONata? Learn How to Query JSON Like a Pro

If you've ever had to extract a single nested value from a massive, unpredictable JSON payload, you know the pain. You end up writing brittle chains of data.map().filter().reduce(), adding endless ?. optional chaining just to prevent your app from crashing.

This is where JSONata comes in. It's a lightweight, incredibly powerful query and transformation language built specifically for JSON. Think of it as XPath or GraphQL, but heavily optimized for standard JSON objects.

What Exactly is JSONata?

Created by Andrew Coleman at IBM, JSONata is an open-source query language that lets you extract, transform, and map data from JSON documents using insanely concise syntax. Instead of writing 15 lines of JavaScript to reshape an API response, you can do it in two lines of JSONata.

Why Devs Love JSONata (Key Features)

1. Dead-Simple Path Navigation

The most basic feature of JSONata is navigating through deeply nested JSON structures without worrying about undefined errors:

JSON
// Sample JSON data
{
  "customer": {
    "name": "John Smith",
    "address": {
      "city": "New York",
      "zipCode": "10001"
    },
    "orders": [
      { "id": "1001", "product": "Laptop", "price": 1200 },
      { "id": "1002", "product": "Smartphone", "price": 800 }
    ]
  }
}

To access the customer's city, you just trace the path:

customer.address.city

Result: "New York"

Path Navigation in JSONata

Path Navigation in JSONata

2. Painless Array Processing

Stop writing .map((order) => order.product). JSONata understands when it hits an array and automatically maps the properties for you:

customer.orders.product

Result: [ "Laptop", "Smartphone" ]

Array Processing in JSONata

Array Processing in JSONata

3. Inline Filtering

You can filter arrays natively right inside the bracket notation:

customer.orders[price > 1000].product

Result: "Laptop"

Filtering and Conditions in JSONata

Filtering and Conditions in JSONata

4. Built-in Functions

JSONata ships with powerful math and string manipulation functions right out of the box:

$sum(customer.orders.price)

Result: 2000

Functions and Transformations in JSONata

Functions and Transformations in JSONata

5. Instant Data Restructuring

Need to reshape the JSON to fit your frontend component? Just declare the object structure you want and map the variables directly inside it:

{
  "customerName": customer.name,
  "totalSpent": $sum(customer.orders.price),
  "orderCount": $count(customer.orders)
}

Result:

JSON
{
  "customerName": "John Smith",
  "totalSpent": 2000,
  "orderCount": 2
}
Data Restructuring in JSONata

Data Restructuring in JSONata

JSONata vs. The Alternatives

JSONata vs. Vanilla JavaScript

Yes, you can do all of this in plain JS. But JSONata gives you:

  1. Conciseness: It shrinks data reshaping code by 80%.
  2. Declarative style: You declare what shape you want, not how to iterate over it.
  3. Safety: Perfect for allowing end-users or product managers to write custom data-extraction scripts without risking arbitrary JS code injection.

JSONata vs. jq

If you operate entirely in the bash terminal, jq is king. But if you are building Node.js/React applications and need to embed complex transformation logic natively, JSONata provides a much more intuitive syntax for JavaScript developers.

Getting Started

Integrating JSONata into your Node/TypeScript project takes seconds:

npm install jsonata

Here's how easily it evaluates:

JavaScript
const data = {
  customer: {
    name: "John Doe",
    orders: [
      { id: 1, item: "Laptop", price: 1200 },
      { id: 2, item: "Phone", price: 800 },
      { id: 3, item: "Tablet", price: 1500 }
    ]
  }
};

// Compile the expression
const expression = jsonata('customer.orders[price > 1000]');

// Evaluate against your dataset
const result = await expression.evaluate(data);  
console.log(result);
Basic Usage of JSONata

Basic Usage of JSONata

Real World Developer Use Cases

1. API Response Formatting (BFF Layer)

When your backend returns way too much garbage data, use JSONata in your "Backend-For-Frontend" layer to instantly strip it down before sending it to the client:

JavaScript
const apiResponse = {
    "records": [
      { "id": 1, "firstName": "John", "lastName": "Doe", "age": 28, "email": "john@example.com" },
      { "id": 2, "firstName": "Jane", "lastName": "Smith", "age": 32, "email": "jane@example.com" }
    ],
    "pagination": { "total": 200, "page": 1, "perPage": 2 }
  };
  
  // Transform straight to the frontend requirement
  const expression = jsonata(`{
    "users": records.{
      "fullName": firstName & " " & lastName,
      "contactInfo": {
        "email": email,
        "age": age
      }
    },
    "totalUsers": pagination.total
  }`);
  
  const result = await expression.evaluate(apiResponse);
  console.dir(result,{depth:null})
API Response Transformation with JSONata

API Response Transformation with JSONata

2. Aggregating Sales Data

JSONata easily handles complex $sum and $average mapping across nested transactions:

JavaScript
const salesData = {
  "transactions": [
    { "category": "Electronics", "amount": 1200 },
    { "category": "Clothing", "amount": 90 },
    { "category": "Electronics", "amount": 500 },
    { "category": "Groceries", "amount": 125 }
  ]
};

// Calculate totals perfectly grouped by category
const expression = jsonata(`{
  "total": $sum(transactions.amount),
  "average": $round($average(transactions.amount), 2),
  "categories": {
    "Electronics": $sum(transactions[category="Electronics"].amount),
    "Clothing": $sum(transactions[category="Clothing"].amount),
    "Groceries": $sum(transactions[category="Groceries"].amount)
  }
}`);

expression.evaluate(salesData)
  .then(result => console.log(JSON.stringify(result, null, 2)))
  .catch(err => console.error('Error:', err));
Data Aggregation and Analysis with JSONata

Data Aggregation and Analysis with JSONata

3. Dynamic Environment Configuration

Inject JSONata scripts to parse generic config templates into exact environment URLs without writing complex JS logic:

JavaScript
const baseConfig = {
    "app": {
      "name": "DevTools App",
      "environments": {
        "development": { "apiUrl": "http://localhost:3000/api", "debug": true },
        "staging": { "apiUrl": "https://staging-api.example.com", "debug": true },
        "production": { "apiUrl": "https://api.example.com", "debug": false }
      },
      "defaults": { "timeout": 5000, "retries": 3 }
    }
  };
  
  async function getConfig(env) {
    const expression = jsonata(`{
      "name": app.name,
      "apiUrl": app.environments.${env}.apiUrl,
      "debug": app.environments.${env}.debug,
      "timeout": app.defaults.timeout,
      "retries": app.defaults.retries
    }`);
    
    const result = await expression.evaluate(baseConfig);
    return result;
  }
  
  getConfig('development').then(result => console.log(result)).catch(error => console.error(error));
  getConfig('staging').then(result => console.log(result)).catch(error => console.error(error));
  getConfig('production').then(result => console.log(result)).catch(error => console.error(error));
Configuration Management with JSONata

Configuration Management with JSONata

Advanced JSONata Features

1. Writing Custom Functions

You aren't restricted to built-ins. You can declare fully custom functions directly inside your JSONata script payload:

JavaScript
const apiResponse = {
    "order": {
        "items": [
            {"name": "Apple","price": 0.99,"quantity": 3},
            {"name": "Banana","price": 0.59,"quantity": 5},
            {"name": "Orange","price": 1.29,"quantity": 2}
        ]
    }
}
const expression = jsonata(`(
    $formatCurrency := function($amount) {
      "$" & $string($round($amount, 2))
    };
    {
      "items": order.items.{
        "product": name,
        "price": $formatCurrency(price),
        "total": $formatCurrency(price * quantity)
      },
      "orderTotal": $formatCurrency($sum(order.items.(price * quantity)))
    }
  )`);
try {
    const result = await expression.evaluate(apiResponse);
    console.dir(result, { depth: null, colors: true });
} catch (err) {
    console.error('JSONata evaluation failed:\n', err);
}
Custom Functions in JSONata

Custom Functions in JSONata

2. Clean Error Handling

Ternary operators let you aggressively fallback to defaults when third-party APIs fail to send the data you expect:

JavaScript
const apiResponse = {
  customer: {
    address: {}
  }
};

// Falls back safely if zipCode is entirely missing
const expression = jsonata(
  `customer.address.zipCode ? customer.address.zipCode : "No ZIP code provided"`
);

try {
  const result = await expression.evaluate(apiResponse);
  console.dir(result, { depth: null, colors: true });
} catch (err) {
  console.error('JSONata evaluation failed:\n', err);
}
Error Handling in JSONata

Error Handling in JSONata

3. Recursive Processing

Need to map a complex file directory tree? JSONata allows self-calling recursion to parse infinite depths effortlessly:

JavaScript
const apiResponse = {
    "rootNode": {
        "name": "root",
        "type": "folder",
        "children": [
            {"name": "file1.txt","type": "file","size": 123},
            {"name": "subfolder","type": "folder",
            "children": [{"name": "file2.txt","type": "file","size": 456}]
            }
        ]
    }
};

// Watch $processNode elegantly call itself
const expression = jsonata(`(
        $processNode := function($node) {
          $node.type = "folder" ? 
            {
              "name": $node.name,
              "type": "folder",
              "children": $node.children.$processNode($)
            } : 
            {
              "name": $node.name,
              "type": "file",
              "size": $node.size
            }
        };
        
        $processNode(rootNode)
      )`);
try {
    const result = await expression.evaluate(apiResponse);
    console.dir(result, { depth: null, colors: true });
} catch (err) {
    console.error('JSONata evaluation failed:\n', err);
}
Recursive Processing in JSONata

Recursive Processing in JSONata

Conclusion

If you spend your days mutating APIs, scraping payloads, or building data pipes, JSONata is fundamentally a superpower. It strips away the imperative boilerplate of JavaScript arrays yielding clean, readable, configuration-driven transformations.

Stop dreading data reshaping grids. Add JSONata to your project and let its elegant syntax do the heavy lifting for you!

JSONata
JSON
Data Transformation
Query Language
Development

Related Posts

JSON to XML Conversion: Complete Developer Guide 2026

Learn how to convert JSON to XML effectively without tearing your hair out. A practical guide to handling arrays, lost data types, and legacy SOAP APIs.

By DevToolLab Team•July 25, 2025

Top 5 Bitly Alternatives in 2026

As link management evolves in 2026, Bitly isn't the only player in town. Discover the best Bitly alternatives for branding, analytics, and tracking starting with DevToolLab's powerful URL Tracker.

By DevToolLab Team•March 22, 2026

Top 5 Local LLM Tools & Models in 2026 (Offline AI Guide)

Compare the best local LLM tools and models for offline AI in 2026. Covers Ollama, LM Studio, LocalAI, hardware needs, and when to choose each option.

By DevToolLab Team•March 21, 2026