Mojo JSON Handling

JSON (JavaScript Object Notation) is the most widely used format for exchanging data between programs, APIs, and configuration files. It is human-readable, language-neutral, and supported everywhere. Mojo handles JSON through Python's built-in json module via the interop layer, giving you full parsing and generation capability.

What JSON Looks Like

  {
    "name": "Alice",
    "age": 30,
    "active": true,
    "scores": [95, 87, 91],
    "address": {
      "city": "Tokyo",
      "country": "Japan"
    },
    "notes": null
  }

  JSON data types:
  ┌────────────┬──────────────────────────┐
  │ JSON       │ Python (via interop)     │
  ├────────────┼──────────────────────────┤
  │ string     │ str                      │
  │ number     │ int or float             │
  │ boolean    │ True / False             │
  │ null       │ None                     │
  │ array      │ list                     │
  │ object     │ dict                     │
  └────────────┴──────────────────────────┘

Parsing JSON: json.loads

from python import Python

fn main() raises:
    var json = Python.import_module("json")

    var raw = '{"name": "Alice", "age": 30, "scores": [95, 87, 91]}'
    var data = json.loads(raw)   # JSON string → Python dict

    print(data["name"])          # Alice
    print(data["age"])           # 30
    print(data["scores"][0])     # 95
    print(data["scores"][1])     # 87
json.loads() flow:
  JSON string: '{"name": "Alice", "age": 30}'
       │
       ▼  json.loads()
  Python dict: {"name": "Alice", "age": 30}
       │
  Access with ["key"] just like a regular dict

Generating JSON: json.dumps

from python import Python

fn main() raises:
    var json = Python.import_module("json")
    var py   = Python.import_module("builtins")

    # Build a Python dict from scratch
    var data = py.dict()
    data["product"]  = "Mojo Compiler"
    data["version"]  = 1
    data["stable"]   = True
    data["features"] = py.list(["SIMD", "parallelism", "ownership"])

    # Convert to JSON string
    var json_str = json.dumps(data, indent=2)
    print(json_str)

Output:

{
  "product": "Mojo Compiler",
  "version": 1,
  "stable": true,
  "features": [
    "SIMD",
    "parallelism",
    "ownership"
  ]
}

Reading JSON from a File

from python import Python

fn main() raises:
    var json = Python.import_module("json")

    # Write a sample JSON file first
    with open("config.json", "w") as f:
        f.write('{"host": "localhost", "port": 8080, "debug": true}')

    # Read and parse it
    var py_open = Python.import_module("builtins").open
    var file    = py_open("config.json", "r")
    var config  = json.load(file)   # parse from file object directly
    file.close()

    print(config["host"])    # localhost
    print(config["port"])    # 8080
    print(config["debug"])   # True

Writing JSON to a File

from python import Python

fn main() raises:
    var json = Python.import_module("json")
    var py   = Python.import_module("builtins")

    var results = py.list()
    for i in range(5):
        var entry = py.dict()
        entry["id"]    = i
        entry["score"] = 80 + i * 4
        results.append(entry)

    # Write to file with pretty formatting
    var outfile = py.open("results.json", "w")
    json.dump(results, outfile, indent=2)
    outfile.close()
    print("Saved results.json")

Output file:

[
  {"id": 0, "score": 80},
  {"id": 1, "score": 84},
  {"id": 2, "score": 88},
  {"id": 3, "score": 92},
  {"id": 4, "score": 96}
]

Navigating Nested JSON

from python import Python

fn main() raises:
    var json = Python.import_module("json")

    var raw = """
    {
        "company": "Modular",
        "language": {
            "name": "Mojo",
            "version": 1,
            "targets": ["CPU", "GPU", "TPU"]
        }
    }
    """

    var d = json.loads(raw)

    # Navigate nested structure
    print(d["company"])                      # Modular
    print(d["language"]["name"])             # Mojo
    print(d["language"]["targets"][0])       # CPU
    print(d["language"]["targets"][1])       # GPU
Nested access diagram:

  d
  ├── "company"  → "Modular"
  └── "language"
        ├── "name"    → "Mojo"
        ├── "version" → 1
        └── "targets" → ["CPU", "GPU", "TPU"]
                              ↑      ↑
                           [0]    [1]

Handling Missing Keys Safely

from python import Python

fn main() raises:
    var json = Python.import_module("json")

    var raw  = '{"name": "Bob", "age": 25}'
    var data = json.loads(raw)

    # Use .get() with a default to avoid KeyError
    var name    = str(data.get("name",    "Unknown"))
    var email   = str(data.get("email",   "not provided"))
    var country = str(data.get("country", "not provided"))

    print("Name:", name)      # Name: Bob
    print("Email:", email)    # Email: not provided
    print("Country:", country) # Country: not provided

JSON API Response Pattern

from python import Python

fn fetch_and_parse(url: String) raises -> PythonObject:
    var requests = Python.import_module("requests")
    var json     = Python.import_module("json")

    var response = requests.get(url)
    if int(response.status_code) != 200:
        raise Error("HTTP error: " + str(response.status_code))

    return json.loads(str(response.text))

fn main() raises:
    # Example with a public API
    try:
        var data = fetch_and_parse("https://api.github.com/repos/modularml/mojo")
        print("Stars:", data["stargazers_count"])
        print("Forks:", data["forks_count"])
        print("Language:", data["language"])
    except e:
        print("API request failed:", str(e))

json.dumps Options

Option                | Effect
----------------------|-------------------------------------------
indent=2              | Pretty-print with 2-space indentation
sort_keys=True        | Sort dictionary keys alphabetically
ensure_ascii=False    | Allow non-ASCII characters (e.g. emoji)
separators=(","," :") | Compact format, no extra spaces

Examples:
  json.dumps(d, indent=4)          → nicely indented
  json.dumps(d, sort_keys=True)    → keys in A-Z order
  json.dumps(d, separators=(",",":")  → minimal whitespace

Key Takeaways

Import Python's json module with Python.import_module("json"). Parse a JSON string with json.loads(text) to get a Python dict or list. Convert a Python object back to JSON with json.dumps(obj, indent=2). Read directly from a file object with json.load(file) and write with json.dump(obj, file). Navigate nested structures by chaining bracket access. Use .get(key, default) to safely access keys that might be absent. The indent, sort_keys, and ensure_ascii options control output formatting.