Thinking of leaving Contentful after the Salesforce deal? A practical guide for small teams
Salesforce completed its purchase of Contentful on 1 September 2026. Contentful says the platform, APIs and support stay the same, and so far there's no sign of a broad price rise. Even so, if you run a few marketing sites or client sites, a renewal under a new owner is a good moment to check you're on the right tool. This guide covers how to decide, and what moving to Mojimoto actually involves.
Blocks or references?
- Use a Blocks field for sections that belong to one page. They live in the entry, publish with it, and never show up as separate entries in the content list.
- Use a References field for content shared between pages, like an author, a testimonial used on three pages, or a site-wide call to action.
- Never park page structure in a JSON field. It gets no editor, no validation and no media handling.
Define the block types
In the model editor, add a field of type Blocks to your page type and describe its block types in the box. One block type per line, its fields indented beneath as name: type. Add ! to make a field required on publish, and put select options in brackets.
hero: Hero heading: symbol! body: rich_text image: media features: Feature list title: symbol! items: text quote: Quote text: text! author: symbol tone: select(light, dark)
Block fields can be symbol, text, rich_text, number, boolean, date, select, media, location or json. Reference fields inside blocks are not supported yet - if a section needs to point at another entry, use a References field on the page for now.
Set Min and Max on the field to limit how many blocks a page can have, for example exactly one hero.
Or define them over the API
The same model as a field definition, for scripts and agents. config.blocks maps each block type to its label and fields:
curl -X POST https://mojimoto.com/api/v1/your-project/manage/content-types/page/fields \
-H "Authorization: Bearer mjmt_your_write_token" \
-H "Content-Type: application/json" \
-d '{
"field": "sections",
"definition": {
"type": "blocks",
"config": {
"label": "Sections",
"blocks": {
"hero": {
"label": "Hero",
"fields": {
"heading": { "type": "symbol", "config": { "label": "Heading", "required": true } },
"image": { "type": "media", "config": { "label": "Image" } }
}
}
}
}
}
}'
Edit them
In the entry editor a Blocks field shows one card per block. Add a block from the menu of types you defined, drag cards to reorder, collapse the ones you are not working on, and remove any you no longer need. Media and rich text work inside blocks exactly as they do anywhere else.
When something is missing, publish tells you exactly where: "Sections, block 2 (Hero): Heading is required." Over the API the same error comes back keyed by position, as sections.1.data.heading.
Write them
A blocks value is an ordered list of { type, data }. Each block is delivered with an id your front end can use as a key. Blocks added in the editor keep theirs for good; when writing over the API, send your own id to keep it stable across edits.
{
"title": "Home",
"sections": [
{ "type": "hero", "data": { "heading": "Welcome", "image": { "asset_id": 12, "fit": "cover" } } },
{ "type": "quote", "data": { "text": "It just works.", "author": "Sam" } }
]
}
Render them
The delivery API returns each block as { id, type, data }, with media expanded to full objects and rich text in its delivered shape. In React, SliceZone maps each block type to a component:
import { SliceZone, type BlockComponents } from '@mojimoto/react';
const components: BlockComponents = {
hero: ({ slice }) => <h1>{slice.data.heading as string}</h1>,
quote: ({ slice }) => <blockquote>{slice.data.text as string}</blockquote>,
};
export function Page({ page }) {
return <SliceZone slices={page.data.sections} components={components} />;
}
Generated TypeScript types include a type for each block, so slice.data is fully typed once you run npx @mojimoto/cli types.
Save a template
- 1 Get one project's content model the way you want it. This becomes the source of the template.
- 2 Open your organisation settings and go to Templates.
- 3 Choose the project, give the template a name like "Small business site", and press Save as template.
A template holds the content model only: types, fields and their settings. Entries, media and tokens stay in the project they came from.