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.

All three mutation methods — $set, $add, and $remove — send a POST request to your server endpoint with the target path encoded as a query parameter (?path=...). Your server must respond with { invalidate: [...] }: an array of dot-separated path strings that the client should consider stale. After receiving this response, the client updates its cache for each listed path (the exact strategy differs per operation — see Cache after mutations) and re-fetches on the next access. Any $on listeners registered on those paths are fired immediately after.

$set — update a value

$set replaces the value at a path. It accepts two forms:
// Replace the value at the current path
await server.posts.page1.$set({ title: "Updated", body: "New content" });

// Set a child key (shorthand for server.posts.page1.title.$set(...))
await server.posts.page1.$set("title", "Updated title");
What the client sends
POST ?path=posts.page1
Content-Type: application/json

{ "title": "Updated", "body": "New content" }
The body is the raw new value — no wrapper object. It can be any valid JSON type: an object, array, string, number, boolean, or null. What the server must return
{ "invalidate": ["posts.page1"] }
The server should invalidate the exact path that changed. The client marks posts.page1 as stale and re-fetches it on next access.

$add — add a new entry

$add appends a new entry to a collection. The server assigns the key, or you can suggest one. Three calling forms are supported:
// Server assigns the key
await server.posts.$add({ title: "New Post", body: "..." });

// Suggest a key (server may override)
await server.posts.$add("page5", { title: "New Post", body: "..." });

// Object form with explicit key
await server.posts.$add({ key: "page5", obj: { title: "New Post" } });
What the client sends All three forms compile to the same POST body shape:
POST ?path=posts
Content-Type: application/json

{ "__op": "add", "key": "page5", "value": { "title": "New Post", "body": "..." } }
The key field is optional — omit it and the server assigns one automatically. What the server must return
{ "invalidate": ["posts"] }
The server invalidates the parent collection so the client re-fetches the updated key list and discovers the newly added entry.

$remove — delete a path

$remove deletes an entry from the store. It can target the current path directly or a named child key:
// Remove the current path
await server.posts.page1.$remove();

// Remove a child key
await server.posts.$remove("page1");
Both forms resolve to the same POST to ?path=posts.page1. What the client sends
POST ?path=posts.page1
Content-Type: application/json

{ "__op": "remove" }
What the server must return
{ "invalidate": ["posts"] }
The server invalidates the parent collection. Unlike $set and $add, the client deletes rather than marks-stale each path in the invalidate list after a $remove, evicting the entry from the cache entirely.

Cache after mutations

After each mutation, the client processes the invalidate array from the server response. The exact behavior differs by operation:
  • $set: object values at each invalidated path are replaced with { __next: true }, a placeholder that triggers a re-fetch the next time any property under that path is accessed. Primitive values at an invalidated path are left in place; they will be refreshed on next access once the parent re-fetches.
  • $add: every invalidated path is set to { __next: true } unconditionally, causing the collection to re-fetch on next access.
  • $remove: every invalidated path is deleted from the cache entirely, evicting both objects and primitives.
This means stale data is never returned — the next await on an invalidated path always goes to the server:
await server.posts.$add({ title: "New Post" });
// posts is now stale — cache holds { __next: true }

const posts = await server.posts; // re-fetches automatically
You can also force any path stale at any time without a mutation:
await server.posts.$refresh();
// same effect: marks posts as { __next: true }
The server must always return {"invalidate": [...]} from mutation endpoints. A missing or malformed response causes the client to throw. An empty array ([]) is valid and tells the client to treat the mutation as a cache no-op.

Build docs developers (and LLMs) love