An essay on Overreacted argues that JSON has been treated too much like a sealed container. If a page depends on JSON today, the client usually has to wait for every byte to arrive, call JSON.parse and only then begin any meaningful work. The writer says that model is too rigid for modern apps, because one slow part of the response holds up everything that follows. In his view, the web has better options than that.

The essay borrows its framing from progressive JPEGs. A progressive image starts fuzzy and gets sharper over time, which makes the first view useful even before the final pass has arrived. The author asks why JSON cannot behave the same way. A streaming parser, he suggests, should be able to expose an incomplete object tree before the stream is done. That would let the client start working earlier, even if some fields are still unresolved.

The catch is that incomplete data is awkward. A partially loaded object can be malformed from the point of view of ordinary code, because the shape is not stable yet and the type checker cannot assume the missing pieces are there. The essay says that is one reason naive streaming JSON has not become common, despite being technically possible. A parser that only hands back half-finished objects is not very pleasant for application logic that expects a complete result.

The more interesting proposal is to change the way data is sent. Instead of streaming an object depth first, the server could send it breadth first, with placeholders for the pieces that are still coming later. Those placeholders can be thought of as promises. The client gets a top-level shell first and then receives additional rows that fill in the gaps. Because the chunks do not need to arrive in strict order, the server can decide what to send now and what to hold back until a slow dependency resolves.

The essay says this is close to how React Server Components work. The client reconstructs a progressively loaded tree as the server streams in rows, and unresolved pieces remain promises until the relevant chunk arrives. That approach lets the page become useful sooner without pretending every dependency has already finished. It also gives the server more freedom to decide whether a piece should be inlined or outlined separately, which can reduce repetition and even support cyclic references.

What the argument ultimately rejects is the idea that streaming should only mean pushing bytes earlier. The real goal, the essay says, is to make earlier bytes actionable. If a client can render a shell, begin work on the data it already has and fill in the rest as promises resolve, the transfer model becomes much more flexible. The result is not just a faster load, but a different shape of application architecture.

The essay’s deeper claim is that earlier bytes should be actionable, not merely earlier. If the client can render a shell, start work on the pieces it already has and let the rest arrive as promises, the application can feel responsive without pretending the data is complete. That is a more demanding model, but also a more useful one.