— Blog / Engineering

What should your AI agent do with a giant JSON file?

Engineering Ishan May 25, 2026 12 min read

Your AI agent just got handed a 1 GB JSON file it has never seen and a question in plain English: how many employees are in California? It can't paste a large JSON file that size into its context window — that's hundreds of millions of tokens. Reach for a naive grep and it gets a confident, wrong answer. This is a field guide to what an agent should actually do when it meets a giant JSON file: worked honestly through jq and ripgrep first, then proven with hard numbers from a schema-blind benchmark.

The problem: an agent meets a file it knows nothing about

Picture the loop a coding agent actually runs. It's told there's a big JSON file at $F and given a goal in English. It does not know the field names, how deep they nest, or how the values are spelled. Before it can answer anything, it has to discover the shape of the data — and here's the part most tooling ignores: every byte the agent reads to figure that out is spent twice, once in latency and once in tokens. A discovery step that dumps half the file into the model's context is a discovery step that has already lost.

To make this concrete we ran a benchmark on a file that behaves like the ones agents trip over in the wild: a 1.03 GB pretty-printed JSON document — a single root object wrapping an employees[] array of 420,295 records, nested about 10 levels deep, with roughly 48 distinct paths. Three tools, six plain-English questions, each tool flying blind with no prior knowledge of the schema. The tools: jq, ripgrep, and the jsonbolt CLI. We'll get to the numbers, but first the two things an agent reflexively tries — and why both fail.

Why you can't just paste it (or grep it)

Pasting is off the table. A gigabyte of JSON is on the order of a quarter of a billion tokens — orders of magnitude past any model's context window, and a small fortune even if it fit. Even the "smart" version, streaming chunks through the model, burns tokens at a ruinous rate for what is really a lookup. (We went deep on the token math in feeding large JSON to an LLM without blowing the context window.)

Grepping is worse, because it looks like it works. The data is full of traps that a text search walks straight into:

The trap. A search for "California" returns zero rows — the file stores it as CA. An agent that doesn't discover the schema first answers confidently and wrong. That's the failure mode that actually hurts: not a crash, a plausible lie.

What the agent actually needs to do (the method)

Strip away the tool choice and every correct answer follows the same three steps. This is the spine of the whole post — judge each tool by how cheaply it gets through it:

A good tool makes all three cheap in both seconds and tokens. Let's see how the usual suspects do.

Approach 1 — jq (great until it isn't)

First, respect: jq has been the right answer for a decade, and under a few hundred megabytes it still is. The trouble at gigabyte scale isn't the query language — it's the parser underneath it. jq keeps no structural index, so it re-reads and re-parses the entire file on every invocation, and "discovery" means dumping the paths of one sampled record and hoping it's representative.

# no structure index, so "discovery" = sample one record's paths and hope
jq '[paths] | unique' # on a 300-record sample → 53s, 2,536 tokens

# then the real query — a full re-parse of all 1.1 GB, every single time
jq '[.employees[] | select(.profile.contact.address.location.state=="CA")] | length' employees.json

jq got every answer right in the end — but its "schema" for the structure task was inferred from a 300-record sample, not the real file, and the cost was steep. Across the six tasks it spent 407 seconds and 8,633 tokens. The re-parse alone measured around 7.6 seconds per query, averaged over 55 calls. And the memory is the part that ends the conversation for truly large files:

The memory crux. jq holds roughly 4 GB of RAM to process a 1 GB file, and it scales about 4:1 — so a 10 GB file points jq at ~40 GB of RAM. That's the wall the word "large" runs into. It's not slow because your filter is clever; it's slow because the parser is the bottleneck.

Approach 2 — ripgrep (fast, but JSON-blind)

The other reflex is ripgrep: if the answer is "find a string," nothing greps faster. But rg reads JSON as plain text. It has no idea what an object or an array is — it infers nesting from indentation, which is a guess that breaks the instant the file is minified, and it can't reconstruct a nested object to hand back.

# ripgrep can't parse JSON — it greps text and guesses structure from indentation
rg -o '"[A-Za-z_]+":' employees.json | sort | uniq -c # 133s, a "schema" by key frequency

# and a naive value search walks straight into the data's traps
rg -c '"state": "California"' employees.json # → 0  (the file stores it as "CA")

On raw speed for literal counts rg is the fastest thing here. But across the six tasks it was correct on only 2 of 6, finishing in 167.9 seconds and 8,625 tokens. The other four looked like answers: the structure task was an indentation guess, the React count needed a human to confirm the matches were really employees, and two more came back partial.

Silent wrongness is the danger. ripgrep was right on only 2 of 6 schema-blind tasks — and the other four didn't announce themselves as wrong. For an autonomous agent, a confident wrong number is worse than a slow right one, because nothing downstream knows to question it.

Approach 3 — the jsonbolt CLI (structure-aware, built for agents)

Now the tool that does the three-step method natively — and the reason this benchmark exists. The jsonbolt CLI — the command you type is jb — is free for personal use, forever, with no file-size cap, and it keeps a structure index instead of re-parsing on every call. So discovery is a single SIMD hardware-accelerated pass, and "locate the field" is a grep over a short list of paths rather than a dump of the whole document. Memory stays roughly 1:1 with the file. Here's step 1 and step 2:

# 1 — list every distinct path, grep to the field you want (one pass, ~0.6s)
jb paths employees.json | grep -i skill
#   .employees[*]…assignedTo.skills.primary
#   .employees[*]…assignedTo.skills.secondary   ← React lives here, not "primary"

# 2 — or get types AND example values in a single call
jb schema employees.json

That grep returns two lines, so it costs a few dozen tokens — not the few hundred jq spends dumping a sample record. Step 3 is the answer itself, and the --ai flag makes the output safe to hand straight to a model:

# count the matches — answer comes back as a single number (2.2s, 143 tokens)
jb search --where '.profile.contact.address.location.state == "CA"' --count employees.json
#   7139

# hand a bounded, context-window-safe slice to the model
jb search --where '.secondary[0] == "React"' --ai employees.json > for_llm.jsonl
#   --ai = --format jsonl --envelope --max-output 1M --max-value-bytes 256
#   each line: {"path": …, "preview": …, "value": …}

Across all six tasks the jsonbolt CLI spent 5,006 tokens and 13.0 seconds at a flat ~1.0 GB of RAM, and it got 6 of 6 correct. That's the whole pitch: pinpoint the field once, then read only what you need.

Free for personal use. The jsonbolt CLI is free for personal use, forever — no file-size limit, plus an --ai flag built for agents. Install it and run it on your own file — grab it from the download page.

The proof: same six questions, three tools, schema-blind

Methodology, briefly. One 1.03 GB pretty-printed JSON file on Apple Silicon, warm page cache, median of five runs, peak RSS measured with /usr/bin/time -l. Token counts use tiktoken's o200k_base on the final stdout the agent reads back — discovery output counts in full; intermediate data piped away inside the shell never enters the model's context and counts zero. Six scenarios, each run by a separate schema-blind agent that had to rediscover the structure from scratch. Tools were jq 1.8.1 and ripgrep 15.1.0. The scripts and raw CSVs behind these numbers live in an open benchmark repo on GitHub.

ToolTotal tokensTotal timePeak RAMCorrect
jsonbolt5,00613.0 s~1.0 GB6 / 6
jq 1.8.18,633407.0 s~4.3 GB6 / 6 *
ripgrep 15.1.08,625167.9 s42 MB–3.1 GB2 / 6

That's roughly 40% fewer tokens, about 31× faster than jq, around 4.2× less memory than jq, and zero silent failures against ripgrep's four. * jq's structure answer was sampled from 300 records, not derived from the full file.

Per-task scorecard

End to end, discovery through extraction. Each cell is time · tokens · verdict; the jsonbolt column is bolded.

The agent's taskjsonboltjqripgrep
Describe the file's structure0.6s · 609 ✓53s · 2,536 (sampled)133s · 2,458 (breaks on minified)
List the distinct skillsets (11)2.2s · 332 ✓63s · 950 ✓18s · 873 (partial)
Find employees with a React skill (140,093)3.8s · 758 ✓65s · 598 ✓8.0s · 867 (needs manual check)
Find projects assigned to an "Alice" (125)2.2s · 2,874 ✓72s · 3,530 ✓3.8s · 3,023 (partial)
Count employees in California (7,139)2.2s · 143 ✓54s · 596 ✓1.3s · 1,128 ✓
Find employees with 8+ years' experience (93,123)2.1s · 290 ✓100s · 423 ✓3.1s · 276 (partial)

Why does the jsonbolt CLI read so few tokens? Because it keeps a structure index, jb paths | grep hands back just the matching paths — tens of tokens, not hundreds. jq has no index, so it dumps a whole sample record's path list and then re-parses all 1.1 GB to run the query. ripgrep harvests key names from indentation, which is sometimes cheap but is fundamentally JSON-blind, so it's the one that quietly gets things wrong.

Where the jsonbolt CLI bites back (honest limits)

No tool is free of edges, and you should know the jsonbolt CLI's before you hit them mid-incident:

We'd rather you know the edges than discover them the hard way. Even with them, the jsonbolt CLI returned all six answers correct and complete.

Still not magic. jb --where can't wildcard inside arrays yet — pipe through awk for that. The honest framing: jq is a query language with a parser attached; the jsonbolt CLI is a parser with a query language attached. On large files, the parser is what's been hurting you.

So what should an agent reach for?

The whole field guide in one table. Match the situation, not the habit:

The situationReach forWhy
File under ~200 MB, a one-off transformjqExpressive and already installed; the parse cost is invisible at that size
A quick literal string checkripgrepFastest grep alive — but verify it; it's JSON-blind
A gigabyte+ file the agent must get rightjsonboltStructure index, SIMD hardware acceleration, sub-second repeat queries, fewest tokens
Feeding results into an LLMjsonboltIts --ai flag emits bounded {path, preview, value} JSONL — capped, context-window-safe
Heavy stateful transforms (reduce, foreach)jqA real query language the jsonbolt CLI deliberately doesn't try to replace

Try it on your own file

If your agent has been choking on a large JSON file, the fastest way to settle it is to run the real tool on the real file:

Run it on the file your agent choked on. The jsonbolt CLI is a free personal-use download — no size cap, no telemetry, no account. Decide on the evidence, not the marketing. And if it earns a spot in your commercial stack, pick up a license — we trust you'll do the right thing.

Frequently asked questions

How should an AI agent query a large JSON file it has never seen?

Build a structure index first, then query only what matters. jb paths lists every distinct path and jb schema adds types and examples, so the agent learns where the data lives without reading the whole file. In our schema-blind test that approach read about 5,000 tokens total across six tasks — roughly 40% fewer than jq or ripgrep.

Can jq handle very large JSON files for AI agents?

Under a few hundred megabytes, comfortably. At the gigabyte scale agents now hit, it re-parses the whole file on every query — about 7.6 seconds per call here — and holds roughly 4 GB of RAM per 1 GB of file, scaling ~4:1. A 10 GB file would push it toward 40 GB of RAM. For repeated queries on a large file, a SIMD-accelerated, structure-aware tool wins on time, tokens, and memory.

Is ripgrep a good way to search large JSON for an LLM?

Only for a quick literal grep. ripgrep is JSON-blind: it guesses structure from indentation, breaks on minified files, can't return nested objects, and misses traps like a state stored as CA rather than California. It was correct on just 2 of 6 schema-blind tasks — and the wrong answers looked like answers.

How do I feed a large JSON file to an LLM without blowing the context window?

Filter at the parser, then bound the output. jb search --where narrows to the matches, and --ai wraps each one as a capped {path, preview, value} JSONL envelope (a shortcut for --format jsonl --envelope --max-output 1M --max-value-bytes 256) so nothing oversized ever reaches the model. More on the trade-offs in the LLM context-window post.

What's the best free CLI for querying large JSON in an AI workflow?

The jsonbolt CLI — free for personal use forever, no file-size cap, and an --ai flag made for agents. It keeps a structure index so jb paths, jb schema, jb search, and jb extract answer in sub-second SIMD-accelerated scans instead of re-parsing. The desktop GUI is free up to 50 MB and activates a license ($89/year or $89 lifetime) for larger files; the CLI has no cap and no activation, so commercial CLI use runs on the honor system — we trust you to make the right call.

Want the surrounding playbook? See how to open a large JSON file when your editor gives up, feeding large JSON to an LLM without blowing the context window, turning a subtree into CSV from a huge file, and — if you want to see the data rather than query it — JSONBolt vs Dadroit for the desktop viewer. Or jump straight to the free download and pricing.

← All posts jsonbolt · v1.4.2