Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/michael-tiger-2010/dragonjson/llms.txt

Use this file to discover all available pages before exploring further.

dragonJSON is built around a single principle: don’t fetch data until it’s needed. Every property access on the server object returns a new Proxy that accumulates the path you’re navigating. No network request is made until you await that Proxy. This means you can pass references to deeply nested paths around your application freely, and the actual HTTP fetch only happens at the last possible moment — when you actually need the value.

The Proxy chain

Under the hood, dragonJSON creates an ES Proxy object at the root. Each property access — server.posts, server.posts.page1, server.posts.page1.title — calls the Proxy’s get trap, which returns a new Proxy carrying the extended path array. No fetch is triggered at any of these steps. The fetch is triggered only when JavaScript’s await mechanism calls the .then property on the Proxy, at which point resolvePath runs.
// No fetch happens yet — just building a path reference
const ref = server.posts.page1.title;

// Fetch happens here — resolvePath(["posts", "page1", "title"]) is called
const value = await ref;
This pattern means you can hold references to paths, pass them between components, and even build abstractions on top of them before any network activity occurs.

Path resolution

When you await a Proxy, dragonJSON calls resolvePath with the accumulated path array. The function follows this logic:
1

Walk the local cache

Starting at rootData (the in-memory cache), resolvePath traverses each segment of the path. It records the index of the first missing segment — either a key that is undefined, or a node that is marked __next.
2

Determine what to fetch

If the cache walk completes without a missing segment, and the final value is not marked __next, the value is returned directly from cache — no HTTP request is made.Otherwise, the function fetches the shallowest missing segment (or the full path if the final node is __next).
3

Merge the response into cache

The response is processed by processBatchData, which merges each returned path into rootData at the correct location. Parent segments are created as needed.
4

Re-traverse

After the fetch completes, resolvePath walks the path again from the root of rootData. Any remaining __next placeholders encountered during the second traversal trigger additional fetches until the full path resolves.

__next placeholder

The server can return { "__next": true } for any node to signal: “this node exists and has children, but I haven’t sent them yet.” The client stores this as a deferred placeholder in rootData. When you later access any child of that node, resolvePath detects the __next flag and issues a fetch for the real data at that point.
{ "__next": true }
This is most useful for deferring expensive subtrees. For example, if posts contains thousands of entries, the server can return __next: true for the top-level posts node when responding to a root fetch. The entries are only loaded when someone actually navigates into posts.
// Server returns { "__next": true } for posts at root fetch time
// No posts data is loaded yet

// This access triggers a real fetch of posts
const firstPost = await server.posts.page1;
The __next hint keeps your initial load fast by letting the server communicate the shape of the data tree without paying the cost of serializing the full subtree.

__more wildcard

{ "__more": true } is a closely related hint for open-ended collections — nodes whose keys the client cannot enumerate in advance. User-generated content, dynamic routes, or any collection where you don’t know all keys up front are good candidates. When resolvePath encounters a __more node and you access a key that isn’t present in the local cache, it treats that key as potentially valid and issues a fetch rather than returning undefined immediately.
// users has __more: true — the client doesn't know which keys exist
// but it will fetch any key you access on demand
const user = await server.users["alice"];
Without __more, accessing an unknown key under a cached node would return undefined without a network call, because the client would assume it already has the full contents of that node. The __more flag overrides this assumption.
Use $prefetch([...keys]) to pre-warm the cache for a list of known keys at a given path, avoiding waterfall fetches.

Build docs developers (and LLMs) love