Need help with your JSON?

Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool

Julia Language: JSON Parsing and Formatting

If you need to work with JSON in Julia today, the shortest path is usually JSON.jl: parse a string or file with JSON.parse, format data with JSON.json, and switch to typed or lazy parsing when the payload gets more complex. This page focuses on the current JSON.jl API, because some older Julia JSON tutorials still describe outdated defaults.

For searchers looking for the right Julia JSON package: JSON.jl is a strong default for general parsing, formatting, JSON Lines, and direct struct decoding. If your codebase already uses JSON3.jl and StructTypes, staying consistent with that stack is also reasonable.

Getting Started with JSON.jl

Install the package once with Julia's package manager, then import it in your project or REPL session:

Install and import

julia> using Pkg
julia> Pkg.add("JSON")

julia> using JSON

The core functions you will use most are JSON.parse, JSON.parsefile, JSON.json, and JSON.print.

Parsing JSON into Julia Values

JSON.parse eagerly reads a JSON string and converts it into Julia values. The important current detail is that JSON objects parse to JSON.Object{String, Any} by default, not a plain Dict.

  • JSON objects become JSON.Object{String, Any}, which preserves insertion order and is designed to feel close to a dictionary.
  • JSON arrays become Vector{Any}.
  • JSON strings become String.
  • JSON numbers become an appropriate Julia number type such as Int64, BigInt, Float64, or BigFloat.
  • JSON booleans become Bool.
  • JSON null becomes nothing.

Basic parsing example

json_text = """
{
  "name": "Alice",
  "age": 30,
  "active": true,
  "tags": ["julia", "json"],
  "profile": {
    "city": "Vilnius",
    "country": "Lithuania"
  },
  "score": null
}
"""

data = JSON.parse(json_text)

println(typeof(data))                 # JSON.Object{String, Any}
println(data["name"])                 # Alice
println(data["tags"][1])              # julia
println(data["profile"]["city"])      # Vilnius
println(data["score"] === nothing)    # true

If a key is also a valid Julia identifier, JSON.Object supports dot-style access too, so data.profile can be convenient in scripts and notebooks.

When to parse into a Dict instead

The default JSON.Object is order-preserving, but key lookups are linear rather than hashed. If you are going to hit the same large object many times, parse into a dictionary up front:

data = JSON.parse(json_text; dicttype=Dict{String, Any})

println(typeof(data))                 # Dict{String, Any}
println(data["profile"]["city"])      # Vilnius

That small option is one of the most useful performance tips when working with bigger Julia JSON payloads.

Parsing directly into structs

Modern JSON.jl can decode JSON straight into your own types, which is often cleaner than pushing around Dict{String, Any} values everywhere.

struct Author
    name::String
    github::String
end

json_text = """{"name":"Ada","github":"ada-dev"}"""

author = JSON.parse(json_text, Author)
println(author.name)                  # Ada

Typed parsing is a good fit for application code, API clients, and any path where you want predictable fields instead of untyped containers.

Large files: lazy parsing

For very large documents, you do not always want to materialize the whole tree at once. JSON.lazy and JSON.lazyfile let you walk the document and materialize only the pieces you touch.

doc = JSON.lazyfile("events.json")

# Access only what you need
first_id = doc.events[1].id[]
println(first_id)

This is especially useful when you only need a few fields from a huge export or API dump.

Reading JSON Files and JSON Lines

Use JSON.parsefile when the data already lives on disk. It supports the same options as JSON.parse, and it also understands JSON Lines files based on the filename extension.

config = JSON.parsefile("config.json"; dicttype=Dict)

# .jsonl and .ndjson are treated as JSON Lines by default
rows = JSON.parsefile("events.jsonl")

# Use missing instead of nothing if that fits your pipeline better
table_like = JSON.parsefile("report.json"; null=missing)

Setting null=missing is a practical choice if the parsed result is headed into table-oriented Julia code where missing is more natural than nothing.

Formatting Julia Values as JSON

Converting Julia data back into JSON is straightforward with JSON.json. Use compact output for transport and pretty output for logs, fixtures, config files, or debugging.

Compact and pretty output

payload = Dict(
    "tool" => "json-formatter",
    "count" => 3,
    "tags" => ["julia", "json"],
    "notes" => nothing
)

compact = JSON.json(payload)
pretty = JSON.json(payload; pretty=2)
pretty_without_nulls = JSON.json(payload; pretty=2, omit_null=true)

println(compact)
println(pretty)
println(pretty_without_nulls)

omit_null=true is useful when you want cleaner API payloads or config files without explicit null fields.

Writing straight to a file

You can write via an IO handle with JSON.print, or write directly by passing a file path to JSON.json.

JSON.json("output.json", payload; pretty=2)

open("compact.json", "w") do io
    JSON.print(io, payload)
end

Formatting your own types

If Julia does not know how to serialize a custom type, define JSON.lower so the object becomes a JSON-friendly structure first.

struct Location
    city::String
    country::String
end

JSON.lower(x::Location) = Dict(
    "city" => x.city,
    "country" => x.country,
)

println(JSON.json(Location("Vilnius", "Lithuania")))

Common Julia JSON Pitfalls

  • Old tutorials may be stale: if a guide says JSON.parse returns a plain Dict by default, it is describing older behavior.
  • nothing is not missing: JSON null maps to nothing unless you explicitly choose null=missing.
  • NaN and Infinity are not valid JSON: JSON.jl can allow them with allownan=true, but only use that for systems that intentionally accept non-standard JSON.
  • Trailing commas and single quotes still fail: if a payload came from hand-edited config, validate it before assuming the parser is wrong.
  • Large repeated lookups can be slow on JSON.Object: use dicttype=Dict when you need hash-based lookup behavior.

Practical Recommendation

For most Julia JSON work in 2026, start with JSON.jl, parse into regular Julia containers or your own structs, and switch on options like dicttype, null=missing, or lazy parsing only when the payload or workload justifies it. That keeps your code simple while still covering large files, typed application models, and human-readable formatting.

Need help with your JSON?

Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool