Progressive JSON
29 points by carlana
29 points by carlana
For those who don’t read articles: This is not a new JSON format or streaming technique. It is RSC explanation.
…and for those who don’t know what RSC is? He mentions the abbreviation once and expands it never. I had no the author was “the react guy” either :-)
The article uses the full term, “React Server Components”, in its Streaming Data vs Streaming UI section.
I do agree that the In Conclusion section would be better if it used the full term instead of “RSC”, as many readers skim.
React’s main docs for Server Components: https://react.dev/reference/rsc/server-components
Funny, I really assumed it to be a streaming technique and didn’t bother to read. Thank you for the tip. RSC is a topic of interest to me.
So much text about streaming JSON and no mention of JSONL?
This article is another in the series from the same author about React Server Components. I think it’s unhelpful to hide the relation between what is written and what it’s really about; in this case I thought the over-engineering is ridiculous, which doesn’t make React look good.
It’s definitely astronaut architecture, but a little philosophizing is good. It lets you think about React from a wider perspective of what sort of problem it’s trying to solve, not the specifics of it. This makes it easier to think about how you would write a tool to do this in some other framework or language or what other approaches might achieve the same goal.
It’s a fictitious format for pedagogical purposes. Using jsonl would require squishing the examples onto a single line.
The real React Server Components format this article is teaching is basically jsonl but with the ID prefixing each line.
They are really trying to teach the concept of the ID slots and how they are filled in later, not how the messages are framed in the stream.
I think you could model the example as a stream of JSONL objects pretty easily, without any need for “ID slots”:
{"_set": {"header": "Welcome to my blog", "footer": "Hope you like it"}}
{"_set": {"post": {"content": "This is my article", "comments": []}}}
{"_append": {"post": {"comments": ["This is the first comment", "This is the second comment"]}}}
{"_append": {"post": {"comments": ["This is the third comment"]}}}
After each streamed JSONL line, the client would have a valid JSON object that could be rendered for the user, and could be updated by subsequently streamed lines, with more-or-less the same results as described in the OP.
If you don’t like those e.g. "_set"
directives, no problem, you could just send the initial object with its full/complete schema, using e.g. null
to represent “pending”, and then just emit partial objects over time, which should be able to make deterministic updates to the common object.
{"header": "Welcome to my blog", "post": {"content": null, "comments": []}, "footer": "Hope you like it"}
{"post": {"content": "This is my article"}}
{"post": {"comments": ["This is the first comment", "This is the second comment"]}}
{"post": {"comments": ["This is the third comment"]}}
The main usecase here is a description of a UI tree, and those get quite deep in practice, so you’d end up with quite a bit of overhead, because every line would need to duplicate a lot of the “wrapper” parts. Also, the streaming often happens out-of-order (by design), so _append
would be non-deterministic (or require extra logic in the server to order things correctly). So an ID-slot based format seems better for the UI tree use-case.
I think JSONL gets 99% of the use cases without the more complicated forward referencing that the proposed extension provides.
The forward-referencing is key for the main use-case of this format, i.e. React Server Components. It’s used for representing a UI tree where some nested parts may arrive later (and a fallback/skeleton UI is displayed while they’re not available). So you need the forward references to be able to express things like “this is a <div class="blah">
, and its children will stream in later”.
I poked around the jsonl package link, jsonl website, and several of the links and could not find anything that referred to streaming or progressive loading. Am I just missing something?
The idea is just that you CAN stream it because every line is its own object. JavaScript has e.g., the ReadableStream type for that.
I see, so each line is a complete object. I think that’s slightly orthogonal to OP’s idea, which is to have a single, large object that hydrates over time. It seems like jsonl would struggle with that use case since you would have to describe the entire object on one line, defeating the purpose.
I think you’re right. I just honestly didn’t understand where he was going with this. My bad :D
apparently, it’s a trap! https://simonwillison.net/2025/Jun/1/progressive-json/
though i don’t find any disingenuousness in the post at all, it was interesting!
i wonder if there’s appetite for a spec?
It would actually be kinda cool.
It is probably more sensible than yaml’s anchors and aliases - and it’s interesting how here the references come before the value. The streamability in any order could be quite useful. There’s plenty of undefined syntax in JSON that could be co-opted.
You could keep streaming over time and patch (partially replace) the values by repeating the reference’s value (which, come to think of it, is a very react thing to want to do, so yeah…).
SBJson has had a form of streaming JSON since 2011. I had high hopes for it, but it made it tricky to write the parser very fast. Lower latency mobile connections coupled with higher download speeds have made it less advantageous too.
Edit: Hah! Sibling comment mentions JSONL, which I had not heard of but should be supported by SBJson. (For parsing at least. SBJson doesn’t produce new lines between records, nor require them when parsing.)