# Applying JOLT to practical use cases

JOLT is widely used in integrations to restructure JSON data, apply business rules, and prepare payloads for downstream systems. It allows you to transform information dynamically, ensuring that each pipeline receives data in the exact structure it needs.

In this guide, you'll find a collection of practical, real-world examples that illustrate how JOLT can solve common transformation challenges.

## **Hands-on examples**

Each example includes:

* The **Input JSON**, demonstrating the original data structure.
* The **desired output**, showing the target format you want to achieve.
* The **JOLT spec**, which you can copy and reuse in your pipelines.
* A clear **explanation** that breaks down the transformation logic.

Together, these examples will help you build confidence in writing and adapting JOLT specifications for your integration use cases.

<details>

<summary><strong>Separating a full name into first name and last name</strong></summary>

This transformation extracts the first and last elements of a full name string and maps them into new fields.

**Input JSON**

```json
{  
    "fullName": "Vitor Aquiles Sordi"
}
```

**Desired output JSON**

```json
{  
    "name": "Vitor",  
    "lastName": "Sordi"
}
```

**Transformation spec**

```json
[
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "fullName": "=split(' ',@(1,fullName))",
      "name": "=firstElement(@(1,fullName))",
      "lastName": "=lastElement(@(1,fullName))"
    }
  },
  {
    "operation": "remove",
    "spec": {
      "fullName": ""
    }
  }
]
```

**Explanation**

The full name is split into a list using spaces as separators. Then, the first and last elements of this list are extracted. The original `fullName` field is removed since it's no longer needed.

</details>

<details>

<summary><strong>Separating the area code from a phone number</strong></summary>

This transformation isolates the first two digits of a phone number (DDD) and extracts the remaining portion as the telephone number.

**Input JSON**

```json
{  
    "telephone": "11999998888"
}
```

**Desired output JSON**

```
{  
    "ddd": "11",  
    "telephone": "999998888"
}
```

**Transformation spec**

```json
[
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "ddd": "=substring(@(1,telephone),0,2)",
      "sizeTelehone": "=size(@(1,telephone))",
      "telephone": "=substring(@(1,telephone),2,@(1,sizeTelephone))"
    }
  },
  {
    "operation": "remove",
    "spec": {
      "sizeTelephone": ""
    }
  }
]
```

**Explanation**

For this type of transformation, and because of how the **substring** function works, we can define the **start** and **end** positions of the snippet we want to extract from a string.

However, phone numbers can vary in length. The `telephone` field may contain:

* A landline number
* A mobile number
* A formatted value such as `"1199999-8888"`

Because of these variations, we chose to use the function **dynamically**.

**How we handle it:**

1. We first calculate the **size** of the value in `telephone`.
2. We then pass that size as a parameter to the `substring` function.

This approach avoids any dependency on the string length and ensures we **always extract the last character**, regardless of the input format.

</details>

<details>

<summary><strong>Removing special characters from CPF and CNPJ</strong></summary>

This transformation removes punctuation and formatting characters from CPF and CNPJ fields.

**Input JSON**

```json
{  
    "cpf": "123.456.789-10",  
    "cnpj": "11.222.333/0001-10"
}
```

**Desired output JSON**

```json
{  
    "cpf": "12345678910",  
    "cnpj": "11222333000110"
}
```

**Transformation spec**

```json
[
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "cpf": "=split('[.-]',@(1,cpf))",
      "cnpj": "=split('[./-]',@(1,cnpj))"
    }
  },
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "cpf": "=join('',@(1,cpf))",
      "cnpj": "=join('',@(1,cnpj))"
    }
  }
]
```

**Explanation**

The **`[ ]`** characters in the `split` function indicate that the parameter should be interpreted as a **regular expression**. Their use is optional, but extremely useful when you want to split a string based on **multiple characters or patterns**.

In the CPF example, using `"[.-]"` ensures that the split happens for **every occurrence** of `"."` **or** `"-"` in the string.

If we removed the brackets — for example: `"=split('.-',(@1,cpf))"` — JOLT would look for the **exact sequence** `".-"`, which does not appear in the CPF value. As a result, the split wouldn't work. The same principle applies to the CNPJ example.

After splitting the values, we use the `join` function to reassemble the segments into a single string without formatting.

</details>

<details>

<summary><strong>Eliminating duplicate values</strong></summary>

This example shows how to deduplicate items inside a list based on a repeating field (`id`).

**Input JSON**

```json
{
  "products": [
    {
      "id": 1
    },
    {
      "id": 2
    },
    {
      "id": 1
    }
  ]
}
```

**Desired output JSON**

```json
{
  "products": [
    {
      "id": "1"
    },
    {
      "id": "2"
    }
  ]
}
```

**Transformation spec**

```json
[
  {
    "operation": "shift",
    "spec": {
      "products": {
        "*": {
          "id": {
            "*": "ids.&[]"
          }
        }
      }
    }
  },
  {
    "operation": "shift",
    "spec": {
      "ids": {
        "*": {
          "$": "products[].id"
        }
      }
    }
  }
]
```

**Explanation**

In the first **shift** operation, the expression `*`: `ids.&[]` does two things:

* First, it selects **all values** from the `id` fields.
* Then, it uses each value as a **field name** in the output (`&`), ensuring that every repeated ID becomes a **unique field**.
* Finally, it places all these dynamically created fields into a new **ids list**.

In the second **shift** operation, the expression `$`: `products[].id` takes the **name** of each field generated inside the `ids` list and uses it as the value for the new `id` fields inside the `products` list.

</details>

<details>

<summary><strong>Adding numeric values</strong></summary>

This transformation calculates the total sum of values contained in a list of objects.

**Input JSON**

```json
{
  "products": [
    {
      "id": 1,
      "name": "Product A",
      "value": 10
    },
    {
      "id": 2,
      "name": "Product B",
      "value": 20
    }
  ]
}
```

**Desired output JSON**

```json
{
  "products": [
    {
      "id": 1,
      "name": "Product A",
      "value": 10
    },
    {
      "id": 2,
      "name": "Product B",
      "value": 20
    }
  ],
  "totalValue": 30
}
```

**Transformation spec**

```json
[
  {
    "operation": "shift",
    "spec": {
      "products": {
        "*": {
          "*": "products[#2].&",
          "value": ["products[#2].&", "values[]"]
        }
      }
    }
  },
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "totalValue": "=doubleSum(@(1,valores))"
    }
  }
]
```

**Explanation**

Using the **shift** operation, we first create a `values` list containing all values from the `products` arrays while preserving the entire `products` structure at the end of the transformation.

Next, we apply the **doubleSum** function directly to the `values` list, allowing JOLT to sum all values dynamically.

This approach is especially useful when working with arrays, since JOLT’s arithmetic functions let you process all items in a list at once.

For simpler transformations, you can also apply functions explicitly, for example:

```
"=doubleSum(@(1,firstValue),@(1,secondValue))"
```

</details>

<details>

<summary><strong>Multiplying two numeric values</strong></summary>

Since JOLT has no multiplication function, this example performs equivalent logic using division.

**Input JSON**

```json
{  
    "value1": 10,  
    "value2": 2
}
```

**Desired output JSON**

```json
{  
    "value1": 10,  
    "value2": 2,  
    "inverseValue": 0.5,  
    "finalValue": 20
}
```

**Transformation spec**

```json
[
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "inverseValue": "=divide(1, @(1,value2))",
      "finalValue": "=divideAndRound(2, @(1,value1), @(1,inverseValue))"
    }
  }
]
```

**Explanation**

By using this transformation, the goal is to **simulate a multiplication in reverse**. To do this, we:

* First divide one of the values by **1**.
* Then divide the other value by the **result of that first division**.

This approach is required because the `=divide` and `=divideAndRound` functions **only accept two parameters**, meaning they cannot directly process more than two values at once.

</details>

<details>

<summary><strong>Applying a filter based on field content</strong></summary>

This example filters list elements by matching a substring inside the email field.

**Input JSON**

```json
{
  "clients": [
    {
      "name": "Aquiles",
      "email": "aquiles@gmail.com"
    },
    {
      "name": "Marcos",
      "email": "marcos@outlook.com"
    },
    {
      "name": "Yuri",
      "email": "yuri@gmail.com"
    }
  ]
}
```

**Desired output JSON**

```json
{
  "clients": [
    {
      "name": "Aquiles",
      "email": "aquiles@gmail.com"
    },
    {
      "name": "Yuri",
      "email": "yuri@gmail.com"
    }
  ]
}
```

**Transformation spec**

```json
[
  {
    "operation": "shift",
    "spec": {
      "clients": {
        "*": {
          "email": {
            "*\\@gmail.com": {
              "@2": "gmail[]"
            }
          }
        }
      }
    }
  }
]
```

**Explanation**

In `"*\\@gmail.com"`, we filter the value of the **email** field to return only the addresses that end with **"gmail.com"**.

* The wildcard `*` captures **any content before** `"@gmail.com"`.
* The sequence **"\\@"** is required because the **"@"** symbol must be treated as a **literal character**, not as JOLT’s wildcard `@`.
* At the end of the expression, the **"\\\\"** is used to **escape the backslash itself**, ensuring it is interpreted correctly.

</details>

<details>

<summary><strong>Including default values in a list</strong></summary>

This transformation inserts a default field into each element of a list.

**Input JSON**

```json
{
  "list": [
    { "a": "a", "b": "b" },
    { "c": "c", "d": "d" }
  ]
}
```

**Desired output JSON**

```json
{
  "list": [
    { "a": "a", "b": "b", "e": "e" },
    { "c": "c", "d": "d", "e": "e" }
  ]
}
```

**Transformation spec**

**Option 1 — default**

```json
[
  {
    "operation": "default",
    "spec": {
      "list[]": {
        "*": {
          "e": "e"
        }
      }
    }
  }
]
```

**Option 2 — modify-default-beta**

```json
[
  {
    "operation": "modify-default-beta",
    "spec": {
      "list": {
        "*": {
          "e": "e"
        }
      }
    }
  }
]
```

**Explanation**

* `default` applies values when the field does not exist. Using `list[]` ensures the rule applies to each array entry.
* `modify-default-beta` behaves similarly to `default`, but it does **not** require the array notation (`[]`). When you specify `"list": { "*": { ... } }`, the operation automatically iterates over each element of the array.

</details>

<details>

<summary><strong>Adding values to list elements</strong></summary>

**Adding a fixed value**

This transformation adds the same fixed value to every element of a list.

You can choose how the value should behave:

* **modify-overwrite-beta**: Always sets the value, even if the field already exists.
* **modify-default-beta**: Sets the value **only if the field does not already exist**.

**Input JSON**

```json
{
  "happy": "true",
  "statistics": [
    {
      "id": "A",
      "min": "2.0",
      "max": "10.0",
      "avg": "7.9"
    },
    {
      "min": "6",
      "max": "6",
      "avg": "6"
    },
    {
      "id": "C"
    }
  ]
}
```

**Desired output JSON**

```json
{
  "happy": "true",
  "statistics": [
    {
      "id": "A",
      "min": "2.0",
      "max": "10.0",
      "avg": "7.9",
      "newValue": "test123"
    },
    {
      "min": "6",
      "max": "6",
      "avg": "6",
      "newValue": "test123"
    },
    {
      "id": "C",
      "newValue": "test123"
    }
  ]
}
```

**Transformation spec**

```json
[
  {
    "operation": "modify-overwrite-beta",
    // To add the value only if it does not exist, change the operation to "modify-default-beta"
    "spec": {
      "statistics": {
        "*": {
          "newValue": "test123"
        }
      }
    }
  }
]
```

**Adding dynamic values**

In this scenario, each list element receives a value retrieved dynamically from another location in the JSON.

The syntax `"@(n,path)"` means: **go up n levels from the current location and then follow the path to find the value**.

**Input JSON**

```json
{
  "levelA": {
    "levelB": {
      "happy": "true"
    }
  },
  "levelX": {
    "statistics": [
      {
        "id": "A",
        "min": "2.0",
        "max": "10.0",
        "avg": "7.9"
      },
      {
        "min": "6",
        "max": "6",
        "avg": "6"
      },
      {
        "id": "C"
      }
    ]
  }
}
```

**Transformation**

```json
[
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "nivelX": {
        "statistics": {
          // "*" = each list element (also counts as a level)
          "*": {
            "newValue": "@(5,levelA.levelB.happy)"
          }
        }
      }
    }
  }
]
```

**Explanation**

* `"*"` iterates over every element in the `statistics` list.
* `"@(5,levelA.levelB.happy)"` climbs **five levels up** (each `"*"` also counts as a level), reaching the root.
* From there, the transformation reads the value of `levelA.levelB.happy`.
* Each list element receives that dynamic value.

</details>

<details>

<summary><strong>Formatting dates using split and concat</strong></summary>

This example demonstrates how to reformat a date by splitting it into parts and then concatenating the reordered values.

The transformation uses `split` to break the string into an array and `concat` to rebuild the date in the desired format (YYYYMMDD).

**Input JSON**

```json
{  
  "data": {    
    "DATE": "18/09/1974"  
  }
}
```

**Desired output JSON**

```json
{  
  "DATE": "19740918"
}
```

**Transformation spec**

```json
[
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "data": {
        "array_aux": "=split('/',@(1,DATE))",
        "DATE": "=concat(@(1,array_aux[2]),@(1,array_aux[1]),@(1,array_aux[0]))"
      }
    }
  },
  {
    "operation": "shift",
    "spec": {
      "data": {
        "DATE": "&"
      }
    }
  }
]
```

**Explanation**

**How the formatting works**

* We use the **modify-overwrite-beta** operation to update the JSON content.
* The `split` function breaks the original date (`18/09/1974`) into an array: `["18", "09", "1974"]`. It uses the "/" character as the delimiter.
* After splitting, the `concat` function reorders the array items to form the final date:\
  `year + month + day` → `"1974" + "09" + "18"`.

{% hint style="info" %}
The `split` function can also receive regular expressions as parameters. For more examples, refer to: [Split Functions tests on GitHub](https://github.com/bazaarvoice/jolt/blob/7812399d1c955742d81eae363244a2d0ef86cf3b/jolt-core/src/test/resources/json/modifier/functions/stringsSplitTest.json).
{% endhint %}

* In the final `shift`, we move the transformed `DATE` field to the root of the output JSON.

</details>

<details>

<summary><strong>Applying simple IF-ELSE logic</strong></summary>

When transforming data between systems, it's common to need a field that doesn't have a direct match in the source JSON. In many cases, you can derive this value using a simple **IF-ELSE** condition inside a JOLT transformation.

This example shows how to determine a client’s **citizenship** based on their **country**.

**Input JSON**

```json
{ 
  "client": {   
    "name": "Sample client",   
    "age": "32",   
    "maritalStatus": "Single",   
    "country": "Brazil" 
  }
}
```

**Desired output JSON**

```json
{
  "client": {
    "name": "Sample client",
    "citizenship": "Brazilian"
  }
}
```

**Transformation spec**

```json
[
  {
    "operation": "shift",
    "spec": {
      "client": {
        "name": "client.name",
        "country": {
          "Brazil": {
            "#Brazilian": "client.citizenship"
          },
          "*": {
            "#Foreigner": "client.citizenship"
          }
        }
      }
    }
  }
]
```

**Explanation**

* The `"country"` field is evaluated using JOLT’s pattern-matching structure:
  * If the value is `"Brazil"`, the literal `Brazilian` is assigned to `client.citizenship`.
  * For any other value (`*` wildcard), the literal `Foreigner` is used.
* The `#` operator creates a **constant value** during the transformation.
* The result is a clean JSON containing only the required fields: **name** and the derived **citizenship**.

</details>

## **Final considerations**

With the concepts and examples covered in this guide, you now have a solid foundation to build powerful JOLT transformations, from simple restructuring to more advanced data manipulation for integration scenarios.

If you want to keep learning, we offer two great resources to support you:

* [**Digibee Academy: Transformer JOLT – Fundamentals**](https://digibee.academy/courses/transformer-jolt/)**:** A structured learning path where you can dive deeper into the operations and operators.
* [**AI Assistant for Connectors**](https://app.gitbook.com/s/jvO5S91EQURCEhbZOuuZ/development-cycle/build-overview/canvas/connector-ai-assistant)**:** Your built-in helper for creating and adjusting JOLT specs directly while building pipelines.

These tools complement your knowledge and make it even easier to design transformations that are correct, efficient, and ready for production.
