← All writing

ADL vs json-server

json-server Was Right, and Nobody Followed the Thought

TL;DR: json-server is one of the most-installed backend tools in existence, and its entire premise is that a data file, interpreted, is a working API. The industry accepted this instantly — for prototypes. ADL is what happens if you refuse to stop there. The gap between the two is not ideology; it is the concrete list of things a production backend must be correct about, and closing that gap is exactly what an application definition language has to pay for.


The steelman

json-server deserves more respect than it usually gets in essays like this one.

Give it a JSON file:

{
  "posts": [{ "id": 1, "title": "Hello", "authorId": 1 }],
  "users": [{ "id": 1, "name": "Ada" }]
}

and in one command you have a REST API: full CRUD on /posts and /users, filtering, pagination, sorting, full-text search, relationship expansion via _embed and _expand. No schema language to learn, no build step, no configuration. The learning curve is measured in seconds, and the tool does exactly what it promises, nothing more, and it never pretended otherwise.

That restraint is a feature. Millions of frontend developers have used json-server to unblock themselves while a real backend was being built. It is arguably the most successful developer tool in its weight class precisely because it made one clean bet and never diluted it.

But look at what that bet actually was, because it’s more radical than it appears: there is no application code. Nobody generates an Express project from db.json. Nobody scaffolds route handlers and then maintains them. The file is read by an interpreter, and the interpreter serves the API. Change the file, the API changes. The description is the software.

Every developer who has ever typed npx json-server db.json has already accepted the core architectural claim behind ADL. They accepted it without argument, without a whitepaper, without a single “but where’s the code?” objection, because it obviously works.

Then the project gets real, and everyone abandons the model.

The question worth asking

Why?

The standard answer is that json-server is a toy, and the standard answer is correct — but it’s correct in an interesting way. json-server isn’t a toy because interpretation is a toy architecture. It’s a toy because the file format can’t say enough. db.json can describe records. It cannot describe:

  • who may read or write them,
  • what makes a record valid,
  • which values a field may legally move between,
  • what should happen when it moves,
  • which fields are derived from others,
  • what must be remembered about who changed what, and when.

So when those requirements arrive (and they always arrive), the file has nothing to say, and the developer reaches for a framework. The lesson the industry took from this was “declarative files are for mocks; production needs code.” That is the wrong lesson. The file didn’t fail because it was interpreted. It failed because its vocabulary ran out.

The right question was never “when do we graduate from the file to the code?” It was “what would the file have to be able to say?”

What the file has to say

ADL is one answer to that question, and the answer is not small. Where db.json says records exist, an ADL domain says, in the same declarative register:

Who may act. Permissions per operation and per field, from role arrays down to expressions — update: "user.id == record.authorId || hasRole('admin')" — enforced on every request, with restricted fields stripped from responses rather than nulled.

What is valid. Field constraints plus cross-field rules that can consult other records: a manager must belong to the same department, a published article requires an excerpt. All violations collected and returned at once, under a stable error contract.

How state may move. State machines with role-guarded transitions, required fields per transition, and side effects on entry and exit. Direct writes to the controlled field are intercepted, so the lifecycle cannot be bypassed by a well-crafted PATCH.

What is derived. Computed fields (virtual, materialized, and aggregations that recalculate when related records change) that appear in responses like ordinary fields and silently ignore client-supplied values.

What is remembered. History, audit, and the rest of the per-resource feature set, switched on declaratively rather than reimplemented per project.

None of this is exotic. It is the standard checklist of things a backend must be correct about: the exact list whose absence makes json-server a mock. The difference is that ADL keeps all of it in the file, and the file is still interpreted, not compiled into a codebase you then own. kalosd reads the YAML and serves the application, the same way json-server reads db.json and serves the mock. Change the file, the application changes.

json-server stops where the business logic starts. ADL is the refusal to stop.

The honest concession

Here is the cost, stated without softening: the vocabulary is the price.

json-server asks you to learn nothing. Its input format is the JSON you already have, and its semantics fit in a README. ADL’s reference runs to forty-four chapters, because expressing permissions, validation, state, derivation, and history precisely requires a real language with real rules: evaluation order for permission checks, hook ordering around state transitions, the exact semantics of a materialized aggregation when a related record is deleted. Every one of those chapters is a thing you can now say in the file, and also a thing you can now get wrong in the file.

There is no version of this trade that comes free. A description language rich enough to replace application code is rich enough to require study. If your need is a mock API for a frontend sprint, json-server is the better tool, and reaching for ADL would be using a mill to crack a nut. The claim here is narrower and stronger: the architecture json-server proved at the prototype scale does not expire at the production boundary. Only its vocabulary does.

Closer

json-server showed everyone that the file can be the API; ADL is what it costs to let the file be the application.