Content JSON

Blobify writes content as JSON documents in your bucket.

Each entry can have:

  • one mutable draft.json
  • one published.json snapshot containing the currently published locales

Draft document

Draft content is used by the dashboard and editors.

jsoncode
{
  "id": "art_123",
  "model": "article",
  "created": "2026-03-01T10:00:00.000Z",
  "publishedLocales": ["en"],
  "published": {
    "en": "2026-03-02T09:00:00.000Z"
  },
  "firstPublished": "2026-03-02T09:00:00.000Z",
  "lastPublished": "2026-03-02T09:00:00.000Z",
  "fields": {
    "title": { "en": "Hello world" },
    "slug": "hello-world",
    "excerpt": { "en": "Short summary" },
    "coverImage": { "type": "asset", "assetId": "img_456" },
    "author": { "type": "reference", "id": "author_1", "model": "author" }
  }
}

Published document

Published content is what your website or app reads.

It keeps only the locales that have actually been published.

jsoncode
{
  "id": "art_123",
  "model": "article",
  "created": "2026-03-01T10:00:00.000Z",
  "publishedLocales": ["en"],
  "published": {
    "en": "2026-03-02T09:00:00.000Z"
  },
  "firstPublished": "2026-03-02T09:00:00.000Z",
  "lastPublished": "2026-03-02T09:00:00.000Z",
  "fields": {
    "title": { "en": "Hello world" },
    "slug": "hello-world",
    "excerpt": { "en": "Short summary" },
    "coverImage": { "type": "asset", "assetId": "img_456" }
  }
}

Localized fields

Localized fields are stored as locale maps:

jsoncode
{
  "title": {
    "en": "Welcome",
    "is": "Velkomin"
  }
}

Non-localized fields are stored once:

jsoncode
{
  "slug": "welcome"
}

References

Content references are stored as semantic references, not fully expanded documents:

jsoncode
{
  "author": {
    "type": "reference",
    "id": "author_1",
    "model": "author"
  }
}

Asset fields follow the same idea:

jsoncode
{
  "coverImage": {
    "type": "asset",
    "assetId": "img_456"
  }
}

Clients resolve these through summaries or asset metadata when rendering.

Rich text shape

Rich text is stored as an AST.

jsoncode
{
  "content": {
    "en": {
      "type": "root",
      "children": [
        {
          "type": "paragraph",
          "children": [
            { "type": "text", "value": "Hello world" }
          ]
        },
        {
          "type": "contentRef",
          "ref": {
            "type": "reference",
            "id": "art_999",
            "model": "article"
          },
          "children": [{ "type": "text", "value": "Read next" }]
        }
      ]
    }
  }
}

Embedded blocks live inside the AST as block nodes:

jsoncode
{
  "type": "block",
  "block": {
    "type": "callout-block",
    "id": "blk_1",
    "heading": { "en": "Important" },
    "body": { "en": "This is a callout." }
  }
}

Why this shape matters

This keeps Blobify predictable:

  • the dashboard edits one draft document
  • websites read one published document
  • references stay stable even if URLs change
  • generated clients can resolve content consistently