Skip to content

Live JSON

Try the interactive example ↓

A real-time collaborative JSON document store: documents carry arbitrary JSON content plus metadata, support full replacement and JSONPath patching, cooperative locks with expiry, and a per-document WebSocket that streams changes at subscribed paths.

When to reach for it: shared application state that several clients edit and watch - collaborative settings panels, live dashboards, game or agent blackboards, any JSON blob where "someone changed it" must reach other clients instantly.

When not to: ephemeral broadcast with no document behind it belongs to Pub/Sub; plain JSON storage with TTL, tags, and search - but no change feed - belongs to the KV Store.

Concepts

  • A document is content plus metadata. Content is any JSON value; metadata is the name, description, tags, TTL, size, owner, and lock state. IDs are auto-generated (doc_...) unless you pass --id.
  • Reads have three views - meta (the default), content, and full. A bare get returns metadata only, not your JSON; this is the most common surprise.
  • Two write granularities - replace the entire content, or patch a single JSONPath with set, delete, append, or insert.
  • The document ID is the capability. Any authenticated user who has the ID can read the document and patch its content. Owner-only operations are delete, metadata updates, replace, and put of an existing document. list shows only your own documents, so handing out an ID is how you share one.
  • Locks are cooperative write exclusivity - while one user holds a lock, other users' content writes fail with 409; the lock expires on its own.
  • Realtime is per-document - each document has its own WebSocket endpoint, and subscriptions watch a JSONPath within it. See Real-time subscriptions.

Create and read

snug live-json create -c '{"count":0,"theme":"light"}' -n "My Counter"
snug live-json create -c '{"a":1}' --id build-status --ttl 300

snug live-json get -d doc_vgDjAtvHYhar                 # metadata only (default)
snug live-json content -d doc_vgDjAtvHYhar             # JSON body only
snug live-json full -d doc_vgDjAtvHYhar                # both
snug live-json get -d doc_vgDjAtvHYhar --view content  # same as the shortcut

The create response returns only id and created_at - fetch metadata (owner, size, lock state, TTL) with get. Over HTTP the same create is POST /api/v1/live-json/documents:

curl -X POST -H "Authorization: Bearer $SNUG_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content": {"count": 0}, "name": "My Counter"}' \
  http://localhost:4000/api/v1/live-json/documents
{
  "status": 201,
  "msg": "Created",
  "data": {
    "id": "doc_jbnMLXXKbDYP",
    "created_at": "2026-08-28T04:33:59.074801Z"
  }
}

Reading a missing document is 404 NOT_FOUND.

Updating content

patch edits one JSONPath; replace swaps the whole content; put creates-or-replaces the document itself at a chosen ID (and is owner-only when the document already exists):

snug live-json patch -d doc_vgDjAtvHYhar -p '$.count' -v '5'            # set (default)
snug live-json patch -d doc_vgDjAtvHYhar -p '$.items' -v '"b"' -o append
snug live-json patch -d doc_vgDjAtvHYhar -p '$.theme' -v 'null' -o delete
snug live-json replace -d doc_vgDjAtvHYhar -c '{"count":5,"items":["a"]}'
snug live-json metadata -d doc_vgDjAtvHYhar -n "Renamed"                # metadata only

The patch operations: set overwrites the value at the path, append pushes onto an array, delete removes the field (-v is still required but ignored). Sibling fields survive a patch; only replace and put are destructive to the rest of the document.

Locking

A lock grants its holder exclusive write access until it expires (default 60 seconds). The full conflict matrix:

snug live-json lock -d doc_vgDjAtvHYhar --duration 120
  • Another user's patch while locked: 409 CONFLICT "Document is locked by another user". The holder's own writes succeed. replace is owner-only (403 for anyone else) and is not gated by the lock.
  • Another user's lock attempt: 409 document_locked.
  • unlock by anyone but the holder: 400 lock_not_held.
  • unlock by the holder releases immediately; otherwise the lock simply expires.

Locks gate content writes only - they do not block reads. For locks not tied to a document, use Distributed State.

Finding documents

snug live-json list --limit 50 --query counter
snug live-json stats

list returns metadata (no content) plus the shared page object (25 per page by default), and only ever your own documents. It takes the shared list options: --query matches names, --filter takes is_shared, content_type, locked, created_at and updated_at, and --sort takes updated_at (the default, newest first), size_bytes or subscriber_count. stats reports live subscription counts: total_subscriptions, documents_watched, connections_active.

Behaviors and gotchas

  • get is metadata by default. Reach for the content or full shortcuts when you want your JSON.
  • Cross-user writes are allowed by design. A second user with the ID can patch your document; use a lock when you need exclusivity. Delete, replace, put of an existing document, and metadata updates by a non-owner fail with 403.
  • --shared is a metadata flag only. It sets is_shared on the document but does not change visibility today: any user with the ID can already read, and list never shows other users' documents.
  • TTL is set at create time (--ttl, seconds) or via metadata; the document expires as a whole.

Real-time change feeds

The WebSocket endpoint, the socket message protocol, the CLI watch command, and the HTTP subscribe API have their own page: Real-time subscriptions.

Reference

Interactive example

Synchronize shared JSON documents across connected clients. Changes reach each subscriber so collaborators can work from the same document.

An illustrative example that runs in your browser. No account or API calls required.