Convert Strings to Numbers in jq Fields and Arrays

All jq tools and guides

Use tonumber to turn a numeric JSON string into a number. Apply it with |= to update a field without dropping the rest of the object, or with map(tonumber) to convert each element of an array. jq does not convert strings implicitly for arithmetic.

Convert a field and an array

Use this JSON input:

{
  "rate": "12.5",
  "quantities": ["2", "4", "0"]
}

Run this jq filter:

.rate |= tonumber | .quantities |= map(tonumber)

Output:

{
  "rate": 12.5,
  "quantities": [2, 4, 0]
}

Run the field and array conversion in the jq playground

|= changes only the selected value; map returns the full array with every element converted. The quotes are gone in the output: 0 is a number, not "0".

Choose what to do with invalid or missing values

For mixed data, use this input:

{
  "items": [
    {"sku":"A","price":"12.5"},
    {"sku":"B","price":"oops"},
    {"sku":"C"},
    {"sku":"D","price":"0"}
  ]
}

To keep records with invalid text or a missing price instead of dropping or silently changing them, use:

.items |= map(
  if has("price") then
    .price |= (
      if type == "string" and test("^-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?$")
      then tonumber
      else .
      end
    )
  else . end
)

Output:

{
  "items": [
    {"sku":"A","price":12.5},
    {"sku":"B","price":"oops"},
    {"sku":"C"},
    {"sku":"D","price":0}
  ]
}

Run the keep-invalid-and-missing policy in the jq playground

The test pattern accepts JSON-style numeric strings (including negative numbers, decimals, and exponents) before tonumber runs. The else . path keeps invalid text or existing non-string values unchanged rather than dropping records. The has("price") guard keeps SKU C's key absent; updating .price without it would create a null field. SKU B remains "oops" so it can be identified and corrected later, while "0" becomes numeric 0. If you want invalid text to fail instead of keeping it, use .items |= map(.price |= tonumber) on this input: jq reports string ("oops") cannot be parsed as a number. On an item with no price, the same strict filter reports null (null) cannot be parsed as a number. Handle those cases deliberately before doing math; neither is converted to zero.

These filters use core jq syntax, verified with jq 1.8.1 and the browser jq playground. For a different way to supply a typed number from the shell, see pass shell variables with --argjson; for more in-place transformations, see update fields and check whether a key exists.

Reference: jq manual: tonumber.