The Tina schema defines the shape of your content. With traditional content management systems you may have done this sort of content modeling via a GUI; however, given its tight coupling to Git, TinaCMS considers the filesystem the ultimate source of truth and leverages a "content-modeling as code" approach.
Your schema is defined in a file called .tina/schema.ts
(only .ts
is supported for now).
// .tina/schema.ts
import { defineSchema } from '@tinacms/cli'
export default defineSchema({
collections: [
{
label: 'Blog Posts',
name: 'post',
path: 'content/posts',
fields: [
{
type: 'string',
label: 'Title',
name: 'title',
},
{
type: 'string',
label: 'Post Body',
name: 'body',
isBody: true,
},
],
},
],
})
Each item in your collections
array represents its own entity.
Note: The
isBody
property is used to output a given field to the markdown body, instead of its frontmatter.
Each of a collection's fields can be of the following type
Specifying list: true
on any field type will turn that field into an array of items:
{
label: "Categories",
name: "categories",
type: "string",
list: true
}
The resulting field in your TinaCMS form will be a list
field. And the resulting data structure would be: ["movies", "art"]
.
Any scalar field can accept an options
array, note that in the example below we're using both options
and list
properties:
{
label: "Categories",
name: "categories",
type: "string",
options: ["movies", "art", "food", "sports"],
list: true
}
In this example, the resulting field in your TinaCMS form will be a checkbox
field. Omitting list: true
(or setting it to false
) would result in a radio
field.
An object type takes either a fields
or templates
property (just like the collections
definition). The simplest kind of object
is one with fields
:
{
label: "Social Media",
name: "socialMedia",
type: "object",
fields: [{
label: "Handle",
name: "handle",
type: "string"
}, {
label: "Service",
name: "service",
type: "string",
options: ["twitter", "instagram", "tiktok"]
}]
}
The resulting data structure would be:
{
socialMedia: {
handle: "tinacms",
service: "twitter"
}
}
Setting list: true
would turn the values into an array:
{
socialMedia: [
{
handle: 'tinacms',
service: 'twitter',
},
{
handle: 'tinacms',
service: 'instagram',
},
]
}
More complex shapes can be built by using the
templates
property. This allows your editors to build out pages using predefined blocks.
The reference
field connects one document to another and only needs to be defined on one side of the relationship. You can specify any number of collections you'd like to connect:
{
label: "Author",
name: "author",
type: "reference",
collections: ["author"] // points to a collection with the name "author"
}
This will result in a resolvable node in your GraphQL structure (Don't worry, we'll discuss how to use the GraphQL API later):
{
getPostDocument(relativePath: $relativePath) {
data {
author {
# disambiguate because could have _many_ collections
... on AuthorDocument {
name
}
}
}
}
}
The resulting field in your TinaCMS form will be a select
field, whose options
are all of the documents in the referenced collections.