C&C Docs
Log in
Platform services

Declaring $data

An app says what its data is in its migrations, and the layer holds every write to that. The examples use the docs' seeded books, reviews and shelves.

A schema, and what its fields promise

A field is required unless it says nullable; it can keep to a list of values, be unique, or have a default. Try each: the layer refuses or fills in, and the page never checks anything itself.

// migrations/000-declare-schemas.json (abridged)
{ "op": "createSchema", "schema": "DataBook", "fields": {
    "title":  { "type": "string" },
    "author": { "type": "string" },                    // required
    "pages":  { "type": "integer", "nullable": true }, // may be left out
    "genre":  { "type": "string",
                "values": ["fiction", "science", "history", "poetry"] },
    "handle": { "type": "slug", "nullable": true, "unique": true },
    "state":  { "type": "string", "default": "on the shelf" },
    "reviews": { "type": "hasMany", "target": "DataReview", "via": "book" } } }

These are writes, and a write is always somebody's. Log in or create an account to try them.

A relation is a field whose type is another schema

There is no join to write. A belongsTo reads back as one object, a hasMany as a list, and both come back in the same query.

// DataReview:  "book":  { "type": "belongsTo", "target": "DataBook" }
// DataBook:    "shelf": { "type": "belongsTo", "target": "DataShelf" }
//              "reviews": { "type": "hasMany", "target": "DataReview", "via": "book" }

await this.$data({
  "_schema": "DataBook",
  "_where": {
    "handle": {
      "$in": [
        "dune",
        "odyssey"
      ]
    }
  },
  "_select": {
    "title": true,
    "shelf": {
      "_select": [
        "name"
      ]
    },
    "reviews": {
      "_select": [
        "stars",
        "body"
      ],
      "_limit": 2
    }
  }
})

A clock time is not an instant

A timestamp is one moment everybody shares. A datetime (and date, time) is what a clock or calendar shows in a named zone: the dentist at 2pm in Toronto stays at 2pm when the clocks change.

// An Appointment schema might declare:
"at":   { "type": "timestamp" }  // an instant everybody shares
"when": { "type": "datetime" }   // a clock time in a named zone

await this.$data.create('Appointment', {
  at:   '2026-06-15T18:00:00Z',                  // the same moment everywhere
  when: '2026-06-15 14:00:00 America/Toronto',   // 2pm in Toronto, even if
})                                               // Toronto's rules change

A migration beside a seed

Each file in migrations/ runs once, in name order, when the app boots. An applied migration is never edited: a change is a new file. Files in seeds/ are rows the app ships, such as the seven books on this page; each names itself with a key, Schema/id, which is how $data('DataBook/dune') finds it.

migrations/                       // run once each, in name order, at boot
  000-declare-schemas.json        // createSchema DataBook, DataReview, …
  050-g3-data-shelves.json        // createSchema DataShelf, addField DataBook.shelf
  054-g3-shelves-grow.json        // addField DataShelf.material
seeds/                            // rows the app ships, synced at boot
  DataBook.json

// seeds/DataBook.json — each row names itself: Schema/id
[ { "_key": "DataBook/dune", "title": "Dune", "author": "Frank Herbert",
    "genre": "fiction", "pages": 412, "shelf": "DataShelf/front-room" }, … ]