Ask an agent to "remember" something across a task and it reaches for the same tool every time: write a JSON file. data.json, state.json, memory.json — the name doesn't matter, the instinct is identical, and for the first few hundred records it's completely fine.
Then it isn't, and the failure doesn't look like a crash. It looks like silent corruption — data that used to be there and now isn't — or a query that takes eleven seconds because "search" means "read the whole file into memory and loop."
The three ways it actually breaks
1. Concurrent writes clobber each other. JSON files have no locking. If two agent runs — or an agent and a cron job, or two tabs of the same app — write to the file close together, one write wins and the other silently disappears. No error, no conflict warning. You find out when the record you were sure you saved isn't there anymore.
2. There's no schema, so there's no enforcement. Nothing stops a number from being stored as "42" one day and 42 the next, depending on which code path wrote it. Every reader has to defensively coerce types, and the bugs this produces are the kind that only surface three weeks later, on one specific record, for no reason anyone can reproduce on demand.
3. "Search" is a linear scan you wrote yourself. grep, Array.filter, a loop with includes() — it all works great until the file has 10,000 records and every lookup means parsing the whole thing first. Typo tolerance, partial matches, ranking by relevance — you end up writing a search engine by hand, badly, one if statement at a time.
The signs you've already crossed the line
- You've added a
.lockfile, a mutex, or a "retry if the write fails" loop — congratulations, you're reimplementing a database's write path, worse. - You've written a one-off migration script to repair a field that got corrupted by a bad write.
- A query that used to return instantly now visibly pauses.
- More than one process — agent, cron job, API route — writes to the same file.
Any one of these means the JSON file has stopped being storage and started being a liability you're actively managing by hand.
What to do about it before it happens
You don't need a full Postgres install to fix this — that's usually the exact reason people put it off. What you actually need is a schema that's enforced instead of hoped for, writes that don't silently clobber each other, and search that isn't a hand-rolled loop. A serverless Postgres-backed store gets you all three without you standing up infrastructure yourself: point the agent at it with the same "write this record" instinct it already has, and the enforcement happens underneath instead of three weeks later in production.
That's the specific gap our Xata Database Kit closes — one skill file that routes an agent's storage through a real schema and full-text search instead of a flat file, for exactly the point where data.json stops being enough. But the actual fix, kit or not, is the same one: the moment you catch yourself writing a lock file or a corruption-repair script, that's the file telling you it's time to move.
Top comments (0)