Skip to content
BuildBase

Custom data collections overview

Define a custom data schema, publish it as a version, and store records against it.

A collection is a custom data schema - the structured-data store behind forms, and usable on its own for anything you would otherwise add a table for.

Three levels, and the middle one is the part worth understanding:

LevelWhat it is
CollectionThe named thing, with a slug. Long-lived
VersionOne immutable set of field definitions
RecordOne row, stored against a specific version
curl https://api.console.buildbase.app/api/collections \
  -H "Authorization: $BUILDBASE_TOKEN"

Before you start

Build collections in the console: Content in the left rail, then Collections under Data (step by step: create a collection). Every endpoint here is token-authenticated - there is no public read path, so a collection is not a substitute for a public CMS API.

Versions are the schema

Fields do not live on the collection. They live on a version, so changing the schema means publishing a new version rather than editing the old one - and records stay readable against the version they were written under.

A version is created with live: false. Setting live: true publishes it: it is refused with 400 "Fields must be added first" on a version with no fields, and it marks every older version of the collection deprecated, so one version is live at a time.

Warning

A live version cannot be edited. PATCH on one returns 400 with "Cannot update live version". This is deliberate - records already point at it, so editing its fields would change the meaning of stored data.

To change a schema, create a new version and publish that.

Field types

Each field on a version has one type: text, rich-text, email, link, color, number, integer, bool, date, select, multi-select, money, location and file. Note the name bool - not boolean.

Field types has what each one stores, its settings (lengths, ranges, patterns, choices, a money field's currency) and the errors a write can get.

Each field carries slug, title, helpText, type, required, and defaultValue. The slug is the key records are stored under.

File fields

A file field holds an image - JPEG, PNG, GIF, WebP or SVG - as one of your assets, never the bytes themselves. It has no default value; it has two settings instead:

SettingMeaningRangeDefault
maxMbThe largest file it takes, in MB0.1 to 1005
maxFilesHow many files it takes in one record1 to 101

Your plan's own per-file limit still applies below maxMb.

A record stores what the file is:

{
  "receipt": {
    "assetId": "6ace3b0e898d27ef4b7a6a30",
    "name": "receipt.png",
    "size": 900000,
    "mimeType": "image/png"
  }
}

A field whose maxFiles is above 1 stores a list of them, even when it holds one file:

{
  "photos": [
    {
      "assetId": "6ace3b0e898d27ef4b7a6a30",
      "name": "front.png",
      "size": 412000,
      "mimeType": "image/png"
    },
    {
      "assetId": "6ace3b0e898d27ef4b7a6a31",
      "name": "back.png",
      "size": 398000,
      "mimeType": "image/png"
    }
  ]
}

When you write a record yourself, send the asset by id - { "assetId": "..." } or the id alone - after uploading it; for a field that takes several files, send a list of them. The name, size and type are read back from the asset, whatever the request says, and the same asset sent twice is stored once. An empty string clears the field.

The write is refused with 400, naming the field, when an id is not one of your assets, when a list is sent to a field that takes one file, when there are more files than maxFiles, or when a file is larger than the field's maxMb - the same limit a visitor's file on a form is held to. A file over maxMb is named with its exact size and limit, and the answer carries maxBytes and tooLarge (records API). Files count toward your storage like any other upload, and deleting a record leaves its files in your assets.

Endpoints

MethodPathPurpose
GET/api/collectionsList collections
GET/api/collections/:idOne collection
POST/api/collectionsCreate
PATCH/api/collections/:idUpdate name or slug
DELETE/api/collections/:idDelete. Only the person or key that created the collection may: anyone else gets 401, whatever their role, and the console shows Delete to the creator only
GET/api/collections/:collectionId/versionsList versions
GET/api/collections/:collectionId/versions/:versionIdOne version, with its fields
POST/api/collections/:collectionId/versionsCreate a draft version
PATCH/api/collections/:collectionId/versions/:idEdit a non-live version
DELETE/api/collections/:collectionId/versions/:idDelete a version
GET/api/collections/chartRecord counts over time

Reading, writing and deleting records is covered in the records API.

How forms use this

A form is a collection plus a published version plus a public endpoint. Every submission becomes a record carrying collectionId, versionId, formId, and the submitted data.

That is why a form cannot exist without a published version, and why changing a form's fields means publishing a new collection version.

The one difference: form submissions arrive through the public endpoint, which needs no token. Everything on this page does.

Next Steps

  • Field types - what each type stores and checks.
  • Records API - read and delete stored records.
  • Forms - collect records from a public endpoint.