Quickly create Models, Blocks in DatoCMS from your source code.
- Installation
- Configuration
- CLI Commands
- Usage
-
Comprehensive Field & Validator Reference
- Text Fields
- Numeric Fields
- Boolean Fields
- Date & Time Fields
- Media Fields
- Link Fields
- Structural Fields
- Aliases
-
Validators Appendix
date_range
date_time_range
enum
extension
file_size
format
slug_format
image_dimensions
image_aspect_ratio
item_item_type
items_item_type
length
number_range
required
required_alt_title
required_seo_fields
title_length
description_length
rich_text_blocks
single_block_blocks
sanitized_html
structured_text_blocks
structured_text_inline_blocks
structured_text_links
- Type Compatibility Matrix
npm install --save-dev dato-builder
Create a dato-builder.config.js
in your project root:
/** @type {import("dato-builder").DatoBuilderConfig} */
module.exports = {
apiToken: process.env.DATO_CMA_TOKEN, // your DatoCMS CMA token
overwriteExistingFields: false, // create new fields only; existing fields remain untouched
debug: false, // enable verbose logging
modelApiKeySuffix: undefined, // suffix for model API keys (e.g. "page" becomes "page_model")
blockApiKeySuffix: "block", // suffix for block API keys (e.g. "hero" becomes "hero_block")
};
overwriteExistingFields:
false
(default): only new fields are created; updates/deletions are skipped.true
: existing fields matching your code’s API keys are updated, and any extra fields are removed.
-
npx dato-builder run <file|dir>
Build one or more scripts (blocks, models, or whole folders). -
npx dato-builder clear-cache
Wipe the local cache that tracks what’s already been synced.
// datocms/blocks/TestBlock.ts
import { BlockBuilder } from "dato-builder";
export default async function buildTestBlock(): Promise<string> {
const block = new BlockBuilder("Test Block")
.addHeading({ label: "Title" })
.addTextarea({ label: "Description" })
.addImage({
label: "Image",
body: { validators: { required: true } },
});
return block.upsert();
}
void buildTestBlock();
Run it:
npx dato-builder run datocms/blocks/TestBlock.ts
// datocms/models/TestModel.ts
import { ModelBuilder } from "dato-builder";
import buildTestBlock from "../blocks/TestBlock";
export default async function buildTestModel(): Promise<string> {
const testBlockId = await buildTestBlock();
const model = new ModelBuilder("Test Model")
.addHeading({ label: "Title" })
.addTextarea({ label: "Description" })
.addModularContent({
label: "Content",
body: {
validators: { rich_text_blocks: { item_types: [testBlockId] } },
},
});
return model.upsert();
}
void buildTestModel();
Run it:
npx dato-builder run datocms/models/TestModel.ts
npx dato-builder run datocms/
Note: You can add more builder scripts (blocks or models) and then point run
at the parent folder to sync them all in one go.
This reference covers all available fields, grouped by category, along with their configuration options, supported validators, usage examples, and available aliases.
builder.addSingleLineString({
label: "Username",
body: { validators: { required: true, length: { min: 3, max: 20 } } },
options: { placeholder: "Enter username" },
});
builder.addMultiLineText({
label: "Description",
body: {
validators: { sanitized_html: { sanitize_before_validation: true } },
},
});
builder.addMarkdown({
label: "Body",
toolbar: ["bold", "italic", "link"],
});
builder.addWysiwyg({
label: "Content",
toolbar: ["format", "bold", "italic", "link", "image"],
});
builder.addTextarea({
label: "Notes",
placeholder: "Type notes here...",
});
builder.addInteger({
label: "Quantity",
body: { validators: { number_range: { min: 1 } } },
});
builder.addFloat({
label: "Price",
body: { validators: { required: true } },
});
builder.addBoolean({
label: "Published",
});
builder.addBooleanRadioGroup({
label: "Active?",
positive_radio: { label: "Yes" },
negative_radio: { label: "No" },
});
builder.addDate({
label: "Publish Date",
body: { validators: { required: true } },
});
builder.addDateTime({
label: "Event Time",
});
builder.addSingleAsset({
label: "Avatar",
body: {
validators: { required: true, extension: { predefined_list: "image" } },
},
});
builder.addAssetGallery({
label: "Gallery",
body: { validators: { size: { min: 1 } } },
});
builder.addExternalVideo({
label: "Promo Video",
});
builder.addLink({
label: "Author",
body: { validators: { item_item_type: { item_types: ["author_item_type_id"] } } },
});
builder.addLinks({
label: "Related Articles",
body: {
validators: {
items_item_type: { item_types: ["article_item_type_id"] },
size: { min: 1, max: 5 },
},
},
});
builder.addSlug({
label: "URL slug",
url_prefix: "/blog/",
placeholder: "my-post",
body: { validators: { slug_format: { predefined_pattern: "webpage_slug" } } },
});
builder.addLocation({
label: "Venue",
body: { validators: { required: true } },
});
Option A: Dynamic IDs via builder functions
Run each builder first to get its generated API key (ID), then plug those IDs in.
// datocms/models/TestModel.ts
import { ModelBuilder } from "dato-builder";
import buildSectionBlock from "../blocks/SectionBlock";
import buildHighlightModel from "../models/HighlightModel";
export default async function buildTestModel() {
// 1. Build the other blocks/models and capture their API keys:
const sectionBlockId = await buildSectionBlock();
const highlightModelId = await buildHighlightModel();
// 2. Use those IDs in your modular-content validator:
const model = new ModelBuilder("Test Model")
.addHeading({ label: "Title" })
.addTextarea({ label: "Description" })
.addModularContent({
label: "Content Sections",
body: {
validators: {
rich_text_blocks: {
item_types: [sectionBlockId, highlightModelId],
},
size: { min: 1 },
},
},
});
return model.upsert();
}
void buildTestModel();
Option B: Hard-coded IDs
If you already know the API keys (e.g. from a previous run), you can skip the async calls and just list them directly:
// datocms/models/TestModel.ts
import { ModelBuilder } from "dato-builder";
export default function buildTestModel() {
const model = new ModelBuilder("Test Model")
.addHeading({ label: "Title" })
.addTextarea({ label: "Description" })
.addModularContent({
label: "Content Sections",
body: {
validators: {
rich_text_blocks: {
// replace these with the real API keys you got earlier
item_types: ["section_block_item_type_id", "highlight_model_item_type_id"],
},
size: { min: 1 },
},
},
});
return model.upsert();
}
void buildTestModel();
Option A: Dynamic IDs via builder functions
Capture the block ID from your builder before using it:
import { ModelBuilder } from "dato-builder";
import buildHeroBlock from "../blocks/HeroBlock";
export default async function buildPageModel() {
const heroBlockId = await buildHeroBlock();
const model = new ModelBuilder("Page Model").addSingleBlock({
label: "Hero",
type: "framed_single_block",
start_collapsed: true,
body: {
validators: {
single_block_blocks: {
item_types: [heroBlockId],
},
},
},
});
return model.upsert();
}
void buildPageModel();
Option B: Hard-coded IDs
If the block ID is known and stable:
builder.addSingleBlock({
label: "Hero",
type: "framed_single_block",
start_collapsed: true,
body: {
validators: {
single_block_blocks: {
item_types: ["hero_block_item_type_id"],
},
},
},
});
Option A: Dynamic IDs via builder functions
Fetch block IDs before defining your structured text field:
import { ModelBuilder } from "dato-builder";
import buildQuoteBlock from "../blocks/QuoteBlock";
export default async function buildArticleModel() {
const quoteBlockId = await buildQuoteBlock();
const model = new ModelBuilder("Article Model").addStructuredText({
label: "Content",
nodes: ["heading", "link"],
marks: ["strong", "emphasis"],
body: {
validators: {
structured_text_blocks: {
item_types: [quoteBlockId],
},
},
},
});
return model.upsert();
}
void buildArticleModel();
Option B: Hard-coded IDs
List known block IDs directly:
builder.addStructuredText({
label: "Content",
nodes: ["heading", "paragraph", "link"],
marks: ["strong", "emphasis"],
body: {
validators: {
structured_text_blocks: {
item_types: ["quote_block_item_type_id"],
},
},
},
});
builder.addSeo({
label: "SEO",
fields: ["title", "description", "image"],
previews: ["google", "twitter"],
body: {
validators: { required_seo_fields: { title: true, description: true } },
},
});
Some methods are provided as convenient aliases:
Alias Method | Primary Method |
---|---|
addImage |
addSingleAsset |
Example
builder.addImage({ label: "Logo" }); // same as addSingleAsset
Below is a detailed breakdown of each supported validator, including parameter definitions, requirements, and usage examples.
Description:
Accepts dates only inside a specified range.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
min | Date |
No | Earliest allowed date (must be a JavaScript Date object). |
max | Date |
No | Latest allowed date (must be a JavaScript Date object). |
⚠️ At least one ofmin
ormax
must be specified.
Example Usage:
builder.addDate({
label: "Start Date",
body: {
validators: {
date_range: {
min: new Date("2025-01-01"),
// max: new Date("2025-12-31"), // you can omit one side if you only care about an open-ended range
},
},
},
});
Description: Accept date/time values only inside a specified range.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
min |
Date , string
|
No | Minimum datetime |
max |
Date , string
|
No | Maximum datetime |
At least one of
min
ormax
must be specified.
Example:
builder.addDateTime({
label: "Deadline",
body: { validators: { date_time_range: { max: "2025-12-31T23:59:59Z" } } },
});
Description: Only accept a specific set of string values.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
values | Array<string> |
Yes | Allowed values |
Example:
builder.addSingleLineString({
label: "Status",
body: {
validators: { enum: { values: ["draft", "published", "archived"] } },
},
});
Description: Only accept assets with specified file extensions or types.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
extensions | Array<string> |
No | Allowed file extensions |
predefined_list |
image , transformable_image , video , document
|
No | Predefined asset category |
Only one of
extensions
orpredefined_list
must be specified.
Example:
builder.addSingleAsset({
label: "Upload",
body: { validators: { extension: { predefined_list: "image" } } },
});
Description: Accept assets only within a specified file size range.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
min_value | number |
No | Minimum file size value |
min_unit |
B , KB , MB
|
No | Unit for minimum size |
max_value | number |
No | Maximum file size value |
max_unit |
B ,KB ,MB
|
No | Unit for maximum size |
At least one value/unit pair must be specified.
Example:
builder.addSingleAsset({
label: "Image",
body: { validators: { file_size: { max_value: 5, max_unit: "MB" } } },
});
Description: Accept only strings matching a custom or predefined format.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
custom_pattern | RegExp |
No | Custom regex pattern |
predefined_pattern |
email ,url
|
No | Predefined format type |
description | string |
No | Hint shown on validation failure (only with custom) |
Only one of
custom_pattern
orpredefined_pattern
must be specified.
Example:
builder.addSingleLineString({
label: "Email",
body: { validators: { format: { predefined_pattern: "email" } } },
});
Description: Only accept slug values matching a custom or predefined slug pattern.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
custom_pattern | RegExp |
No | Custom regex for slug |
predefined_pattern | webpage_slug |
No | Predefined slug format |
Only one of
custom_pattern
orpredefined_pattern
must be specified.
Example:
builder.addSlug({
label: "Slug",
body: { validators: { slug_format: { predefined_pattern: "webpage_slug" } } },
});
Description: Accept assets only within specified width/height bounds.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
width_min_value | number |
No | Minimum width |
width_max_value | number |
No | Maximum width |
height_min_value | number |
No | Minimum height |
height_max_value | number |
No | Maximum height |
At least one width/height pair must be specified.
Example:
builder.addSingleAsset({
label: "Thumbnail",
body: {
validators: {
image_dimensions: { width_min_value: 300, height_min_value: 200 },
},
},
});
Description: Accept assets only within a specified aspect ratio.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
min_ar_numerator | number |
No | Minimum aspect ratio numerator |
min_ar_denominator | number |
No | Minimum aspect ratio denominator |
eq_ar_numerator | number |
No | Exact aspect ratio numerator |
eq_ar_denominator | number |
No | Exact aspect ratio denominator |
max_ar_numerator | number |
No | Maximum aspect ratio numerator |
max_ar_denominator | number |
No | Maximum aspect ratio denominator |
At least one ratio pair must be specified.
Example:
builder.addSingleAsset({
label: "Banner",
body: {
validators: {
image_aspect_ratio: { eq_ar_numerator: 16, eq_ar_denominator: 9 },
},
},
});
Description: Accept references only to specified model records.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
item_types | Array<string> |
✅ | IDs of allowed model types |
on_publish_with_unpublished_references_strategy |
fail , publish_references
|
No | Strategy when publishing with unpublished references |
on_reference_unpublish_strategy |
fail ,unpublish ,delete_references
|
No | Strategy when referenced record is unpublished |
on_reference_delete_strategy |
fail , delete_references
|
No | Strategy when referenced record is deleted |
Example:
builder.addLink({
label: "Author",
body: {
validators: {
item_item_type: {
item_types: ["author_item_type_id"],
on_publish_with_unpublished_references_strategy: "fail",
},
},
},
});
Description: Accept multiple references only to specified model records.
(Same parameters and strategies as item_item_type
)
Example:
builder.addLinks({
label: "Related Posts",
body: { validators: { items_item_type: { item_types: ["post_item_type_id"] } } },
});
Description: Accept strings only with a specified character count.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
min | number |
No | Minimum length |
eq | number |
No | Exact length |
max | number |
No | Maximum length |
At least one of
min
,eq
, ormax
must be specified.
Example:
builder.addSingleLineString({
label: "Code",
body: { validators: { length: { eq: 6 } } },
});
Description: Accept numbers only inside a specified range.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
min | number |
No | Minimum value |
max | number |
No | Maximum value |
At least one of
min
ormax
must be specified.
Example:
builder.addFloat({
label: "Rating",
body: { validators: { number_range: { min: 0, max: 5 } } },
});
Description: Value must be specified or validation fails.
Example:
builder.addSingleLineString({
label: "Title",
body: { validators: { required: true } },
});
Description: Assets must include custom title or alt text.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
title | boolean |
No | Require a custom title |
alt | boolean |
No | Require alternate text |
At least one of
title
oralt
must be true.
Example:
builder.addSingleAsset({
label: "Image",
body: { validators: { required_alt_title: { title: true, alt: true } } },
});
Description: SEO inputs must include one or more specified fields.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
title | boolean |
No | Require meta title |
description | boolean |
No | Require meta description |
image | boolean |
No | Require social sharing image |
twitter_card | boolean |
No | Require Twitter card type |
At least one field must be true.
Example:
builder.addSeo({
label: "Meta",
body: {
validators: { required_seo_fields: { title: true, description: true } },
},
});
Description: Limits the SEO title length.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
min | number |
No | Minimum length |
max | number |
No | Maximum length |
At least one of
min
ormax
must be specified.
Example:
builder.addSeo({
label: "Meta",
body: { validators: { title_length: { max: 60 } } },
});
Description: Limits the SEO description length.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
min | number |
No | Minimum length |
max | number |
No | Maximum length |
At least one of
min
ormax
must be specified.
Example:
builder.addSeo({
label: "Meta",
body: { validators: { description_length: { max: 155 } } },
});
Description: Only accept specified block models in rich text block nodes.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
item_types | Array<string> |
✅ | IDs of allowed block models |
Example:
builder.addModularContent({
label: "Sections",
body: { validators: { rich_text_blocks: { item_types: ["section_item_type_id"] } } },
});
Description: Only accept specified block models in single-block fields.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
item_types | Array<string> |
✅ | IDs of allowed block models |
Example:
builder.addSingleBlock({
label: "Hero",
body: { validators: { single_block_blocks: { item_types: ["hero_block_item_type_id"] } } },
});
Description: Checks for malicious code in HTML input fields.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
sanitize_before_validation | boolean |
✅ | Sanitize content before validation |
Example:
builder.addMarkdown({
label: "Notes",
toolbar: [],
body: {
validators: { sanitized_html: { sanitize_before_validation: true } },
},
});
Description: Only accept specified block models in structured text block nodes.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
item_types | Array<string> |
✅ | IDs of allowed block models |
Example:
builder.addStructuredText({
label: "Content",
body: { validators: { structured_text_blocks: { item_types: ["quote_item_type_id"] } } },
});
Description: Only accept specified block models in inline block nodes of structured text.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
item_types | Array<string> |
✅ | IDs of allowed block models |
Example:
builder.addStructuredText({
label: "Content",
body: {
validators: { structured_text_inline_blocks: { item_types: ["link_item_type_id"] } },
},
});
Description: Only accept itemLink and inlineItem nodes for specified models in structured text.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
item_types | Array<string> |
✅ | IDs of allowed models |
on_publish_with_unpublished_references_strategy |
fail , publish_references
|
No | Strategy when publishing with unpublished references |
on_reference_unpublish_strategy |
fail , unpublish , delete_references
|
No | Strategy when referenced record is unpublished |
on_reference_delete_strategy |
fail , delete_references
|
No | Strategy when referenced record is deleted |
Example:
builder.addStructuredText({
label: "Content",
body: { validators: { structured_text_links: { item_types: ["author_item_type_id"] } } },
});
Field Class | Validators Supported |
---|---|
SingleLineString | required, unique, length, format, enum |
MultiLineText, Markdown, Wysiwyg, Textarea | required, length, format, sanitized_html |
Integer, Float | required, number_range |
Boolean, BooleanRadioGroup | required |
DateField | required, date_range |
DateTime | required, date_time_range |
SingleAsset | required, extension, file_size, image_dimensions, image_aspect_ratio, required_alt_title |
AssetGallery | size, extension, file_size, image_dimensions, image_aspect_ratio, required_alt_title |
ExternalVideo | required |
Link | item_item_type, required, unique |
Links | items_item_type, size |
Slug | required, length, slug_format, slug_title_field |
Location | required |
ModularContent | rich_text_blocks, size |
SingleBlock | single_block_blocks, required |
StructuredText | length, structured_text_blocks, structured_text_inline_blocks, structured_text_links |
Seo | required_seo_fields, file_size, image_dimensions, image_aspect_ratio, title_length, description_length |