JMESPath Tester

Run JMESPath queries against JSON in your browser — your JSON and queries never leave your browser, and nothing is uploaded.

Or drag and drop a file onto this box, up to 50 MB. The file is read in your browser and never uploaded.

    Examples: click one to load its JSON and query

    Engine: @jmespath-community/jmespath 1.3.0, running in a Web Worker. Your JSON and queries never leave your browser; nothing is stored.

    What is JMESPath?

    JMESPath is a query language for JSON. An expression such as people[?age > `30`].name picks out matching parts of a document and returns them as JSON. It has a written specification and a shared compliance test suite, and the AWS CLI and Azure CLI both use it for their --query option.

    This tester runs @jmespath-community/jmespath 1.3.0, an open-source JavaScript library under the MPL-2.0 licence (source repository), inside a Web Worker. Run through this page's own code, the official compliance suite (16 test files, 892 cases) gives 891 passes. The one difference: a doubled backslash in a raw string becomes one backslash, where the older test expects two. The page follows the JMESPath specification, but the AWS CLI, the Azure CLI and other tools implement it themselves, so edge cases can differ.

    The library also adds features that are not in the specification, and queries that use them fail in tools that implement only the specification. The extra functions are find_first, find_last, from_items, group_by, items, lower, pad_left, pad_right, replace, split, trim, trim_left, trim_right, upper, zip. The extra syntax is arithmetic, let variables, a $ root reference, and slicing of strings (people[0].name[0:3] gives "Ada"). The page notes it under a query that uses any of them.

    How do I filter an array with JMESPath?

    Use a filter expression in square brackets: people[?age > `30`].name returns the names of everyone over 30. The ? starts a condition, backticks hold JSON literals such as numbers, and single quotes hold plain strings. Filters work on arrays only, and an item that fails the condition is simply left out.

    A filter can combine conditions with && and || and call functions, as in people[?contains(tags, 'code')].name, which returns ["Ada Lovelace","Margaret Hamilton"]. Then continue: people[?age > `30`] | length(@) counts the matches and gives 3. To inspect the data first, format the result with the JSON Formatter; the JSON Schema Validator checks its shape.

    How do I flatten and project nested data?

    A projection such as people[*].name applies the part after it to every item in an array. A trailing [] flattens one level of nesting, so Reservations[].Instances[].InstanceId turns nested lists into one flat list. Projections skip null results, which is why missing values never appear in the output.

    Without the flatten, Reservations[*].Instances[*].InstanceId keeps one inner list per reservation and gives [["i-0a1","i-0b2"],["i-0c3"]]. With it, Reservations[].Instances[].InstanceId gives ["i-0a1","i-0b2","i-0c3"]. A multiselect list such as people[*].[name, age] builds one array per item, and a multiselect hash such as people[*].{who: name, years: age} builds one labelled object per item.

    JMESPath vs JSONPath: what is the difference?

    Both select parts of JSON, but they are different languages. JSONPath paths start with $, can search at any depth with .., and always return a list of matches. JMESPath returns a bare value or a list, has built-in functions such as sort_by, and needs an explicit path instead of a recursive search.

    The table runs the same selections in both languages. The JMESPath results come from this page's worker; the JSONPath results come from jsonpath-plus 11.1.1, the library behind the JSONPath Tester, with the same options that page uses. Neither is better: they suit different jobs. For background on JSONPath itself, see the guide to JSONPath.

    The same selections in JMESPath and JSONPath (JSON compact, from the real code)
    SelectionJMESPath and its resultJSONPath and its result
    The same selectionpeople[?age > `30`].name
    ["Ada Lovelace","Grace Hopper","Margaret Hamilton"]
    $.people[?(@.age > 30)].name
    ["Ada Lovelace","Grace Hopper","Margaret Hamilton"]
    One valuepeople[0].name
    "Ada Lovelace"
    $.people[0].name
    ["Ada Lovelace"]
    Searching at any depthpeople[*].address.city
    ["London","New York","Boston"]
    $..city
    ["London","New York","Boston","Paris"]

    The last row is a real difference. JSONPath's $..city finds every city key at any depth, including company.hq.city. JMESPath has no recursive search, so the query has to name each place, for example [people[*].address.city, company.hq.city], which gives [["London","New York","Boston"],"Paris"]. Another: JSONPath always returns a list, JMESPath a bare value.

    Why does my JMESPath query return null?

    A JMESPath query returns null when a key is missing, when the value really is null, or when a step does not apply, such as a filter on something that is not an array. A valid query that matches nothing is not an error, so null alone does not tell you which of these happened.

    Gotchas, each checked with this tool

    • Null and missing look the same. people[2].address is a JSON null and people[2].nothing is a missing key, and both give null. Even type() returns "null" for both.
    • Quote odd identifiers. "first name" gives "Ada", while first name is a syntax error. A dash is a trap: unquoted a-b gives 3 here, because this library reads it as subtraction, whereas a tool that follows the specification only would report a syntax error. Write "a-b".
    • Raw strings are not literals. name == 'London' and name == `"London"` both give true. But age == '30' gives false, because '30' is a string and the age is a number, while age == `30` gives true. A bare word such as name == London is read as a key and gives false.
    • Backtick literals must be JSON. `[1, 2]` gives [1,2], but `foo` is rejected: Syntax error: unexpected end of JSON input or invalid format for a JSON literal: `.
    • Projections drop nulls. people[*].address returns three of four people, and people[*].address.city gives ["London","New York","Boston"], skipping the person whose address is null. Projecting a string, as in people[0].name[*], gives null.
    • Large numbers lose digits. The browser reads JSON numbers as 64-bit floats, so 12345678901234567890 comes back as 12345678901234567000 and 9007199254740993 as 9007199254740992. This page warns before running when the input has integers beyond 253; it has no custom number parser.
    • sort_by needs one key type. sort_by(m, &v) fails with Invalid type: expected (number), received string, while numbers alone work: sort_by(m, &v)[*].v gives [1,2].
    • Function arguments are type-checked. abs(people) fails with Invalid type: abs() expected argument 1 to be type (number) but received type array instead., and length(people, people) fails with Invalid arity: length() takes 1 argument but received 2. Convert text first with to_number(people[0].score), which gives 91.5.
    • Only numbers have an order. people[?name > 'B'].name gives [], because comparing strings with > never matches, while people[?age >= `36`].name gives ["Ada Lovelace","Grace Hopper","Margaret Hamilton"].
    • A key named __proto__. __proto__ gives null when the data has no such key. The library alone would return the empty object prototype there, so the page copies the data into prototype-less objects when a query mentions it. A key named __proto__ in a multiselect hash is dropped by the library, and the page says so under the query.
    • Non-standard syntax is flagged. A query that uses the library's extras, such as lower(), arithmetic, let, $ or string slicing, gets a note listing them, because the AWS CLI and other implementations may reject it.
    • Carets cover syntax errors. The caret marks the first token the parser cannot accept, or the end of the query when it stops too soon. Function and type errors show the message alone.

    What do JMESPath query examples return?

    The examples below were each run through this page's own code against small sample documents. Click any of them in the examples panel above to load its document and query. The output shown is the exact text this tool produced, not typed by hand, and a script re-checks it against the library.

    Sample document "people"

    {
      "people": [
        {
          "name": "Ada Lovelace",
          "age": 36,
          "tags": [
            "math",
            "code"
          ],
          "address": {
            "city": "London"
          },
          "score": "91.5"
        },
        {
          "name": "Grace Hopper",
          "age": 45,
          "tags": [
            "compilers",
            "navy"
          ],
          "address": {
            "city": "New York"
          },
          "score": "88"
        },
        {
          "name": "Linus Torvalds",
          "age": 28,
          "tags": [],
          "address": null,
          "score": "79.25"
        },
        {
          "name": "Margaret Hamilton",
          "age": 52,
          "tags": [
            "apollo",
            "code"
          ],
          "address": {
            "city": "Boston"
          },
          "score": "95"
        }
      ]
    }
    19 examples; the aws and orders documents are in the examples panel (outputs are compact JSON)
    #QueryOutput
    1people[0].name"Ada Lovelace"
    2people[*].name["Ada Lovelace","Grace Hopper","Linus Torvalds","Margaret Hamilton"]
    3people[?age > `30`].name["Ada Lovelace","Grace Hopper","Margaret Hamilton"]
    4people[?address.city == 'London'].name["Ada Lovelace"]
    5people[1:3].name["Grace Hopper","Linus Torvalds"]
    6Reservations[].Instances[].InstanceId["i-0a1","i-0b2","i-0c3"]
    7Reservations[].Instances[?State.Name == 'running'].InstanceId[]["i-0a1","i-0c3"]
    8people[?age > `30`] | length(@)3
    9people[*].[name, age][["Ada Lovelace",36],["Grace Hopper",45],["Linus Torvalds",28],["Margaret Hamilton",52]]
    10people[*].{who: name, years: age}[{"who":"Ada Lovelace","years":36},{"who":"Grace Hopper","years":45},{"who":"Linus Torvalds","years":28},{"who":"Margaret Hamilton","years":52}]
    11sort_by(people, &age)[*].name["Linus Torvalds","Ada Lovelace","Grace Hopper","Margaret Hamilton"]
    12max_by(people, &age).name"Margaret Hamilton"
    13join(', ', people[*].name)"Ada Lovelace, Grace Hopper, Linus Torvalds, Margaret Hamilton"
    14sum(map(&to_number(score), people))353.75
    15people[?contains(tags, 'code')].name["Ada Lovelace","Margaret Hamilton"]
    16keys(people[0])["name","age","tags","address","score"]
    17people[*].address.city["London","New York","Boston"]
    18people[*].not_null(address.city, 'unknown')["London","New York","unknown","Boston"]
    19length(orders[?customer == 'ada'])2

    Which operators and functions does JMESPath support?

    The specification defines 26 built-in functions and a small set of operators: sub-expressions, indexes, slices, wildcards, flatten, filters, pipes, multiselect lists and hashes, comparisons and boolean logic. This page runs a library that adds 15 more functions and some syntax. The tables mark every addition as an extension.

    Operators and syntax
    SyntaxMeaning
    foo.barSub-expression: the key bar inside foo
    foo[0] foo[-1]Index from the start or the end of an array
    foo[*] foo.*Wildcard projection over an array, or over the values of an object
    foo[1:3] foo[::-1]Slice with start, stop and step
    foo[]Flatten one level of nesting
    foo[?bar == `1`]Filter an array by a condition
    a | bPipe: run b on the whole result of a
    [a, b]Multiselect list: a new array
    {x: a, y: b}Multiselect hash: a new object
    && || !Boolean and, or and not
    == != < <= > >=Comparisons; ordering works on numbers only
    @The current node
    'text'Raw string literal
    `json`JSON literal, such as `30` or `[1, 2]`
    "quoted name"Quoted identifier, for keys with spaces, dashes or a leading digit
    &exprExpression reference, passed to functions such as sort_by
    `7` // `2` `7` % `4` `3` * `4`Arithmetic operators + - * / // %, and unary - and + extension
    let $x = a in exprVariables with let expressions extension
    $Reference to the root of the document extension
    name[0:3]Slicing a string, which the specification limits to arrays extension
    Built-in functions in the specification (26)
    FunctionWhat it does
    abs()Absolute value
    avg()Average of an array of numbers
    ceil()Round up
    contains()Is a value in an array, or text in a string
    ends_with()Does a string end with a suffix
    floor()Round down
    join()Join an array of strings with a separator
    keys()Keys of an object
    length()Length of a string, array or object
    map()Apply an expression to every item
    max()Largest number or string
    max_by()Item with the largest key
    merge()Merge objects
    min()Smallest number or string
    min_by()Item with the smallest key
    not_null()First argument that is not null
    reverse()Reverse an array or string
    sort()Sort numbers or strings
    sort_by()Sort items by an expression
    starts_with()Does a string start with a prefix
    sum()Sum of an array of numbers
    to_array()Wrap in an array
    to_number()Convert text to a number
    to_string()Convert to a JSON string
    type()Type name of a value
    values()Values of an object
    Extra functions in this library (15)
    FunctionWhat it does
    find_first()Index of the first match in a string extension
    find_last()Index of the last match in a string extension
    from_items()Build an object from key and value pairs extension
    group_by()Group items by an expression extension
    items()Key and value pairs of an object extension
    lower()Lower-case a string extension
    pad_left()Pad a string on the left extension
    pad_right()Pad a string on the right extension
    replace()Replace text in a string extension
    split()Split a string into an array extension
    trim()Trim whitespace from both ends extension
    trim_left()Trim whitespace at the start extension
    trim_right()Trim whitespace at the end extension
    upper()Upper-case a string extension
    zip()Pair up items of arrays extension

    Is my JSON uploaded?

    No. The query runs in a Web Worker on your device, so your JSON and queries never leave your browser. Nothing you paste or upload is sent to a server, and nothing is stored. Still, do not paste secrets into any website, because pages can load third-party scripts such as the Google tag.

    Queries run in the worker under a time limit with a Cancel button, and results above about 20 MB are not built. New to JSON? Read the introduction to JSON.

    Frequently Asked Questions

    Which JMESPath library does this tester use?

    It runs @jmespath-community/jmespath 1.3.0 in a Web Worker in your browser. In this page's own test run it passes 891 of the 892 cases in the official JMESPath compliance suite, and it adds extra functions and syntax beyond the specification, which the page marks as extensions.

    Will my query behave the same in the AWS CLI or Azure CLI?

    Usually, for queries written to the specification, but this page does not claim an exact match. Each command line tool has its own implementation, so edge cases can differ, and the extensions this library adds will not work in tools that implement only the specification.

    Why do large numbers change in the result?

    The browser reads JSON numbers as 64-bit floating point, so integers beyond 2^53 can lose digits before any query runs. The page warns when it sees such numbers. If you need every digit, keep long identifiers in strings.

    How big can the JSON and the query be?

    Uploads can be up to 50 MB, queries up to 10,000 characters, and nesting up to 5,000 levels. Above about 1 MB live mode pauses and you press Run query, and results above about 20 MB are not built. Runs have a time limit and can be cancelled.

    Is my JSON uploaded?

    No. Your JSON and queries never leave your browser. The tester runs in a Web Worker on your device and nothing is stored. Still, do not paste secrets into any website.

    Built and maintained by Deepak Kumar. Your JSON and queries never leave your browser, and nothing you paste is uploaded.