Sorry, no results found for "".
We strongly recommend reading the Introduction to Records guide first. The payload for updating a record follows the same structure as creating one, so that guide is also an essential prerequisite.
The fundamental rules for structuring field values (i.e., strings, numbers, objects, references) are the same for both creating and updating records. For a complete reference on how to format the value for every field type, please see the Field Types Overview in the main records guide.
When updating an existing record, you only need to provide the fields you want to change. Any fields you omit from your payload will remain untouched.
import { buildClient } from "@datocms/cma-client-node";
async function run() { // Make sure the API token has access to the CMA, and is stored securely const client = buildClient({ apiToken: process.env.DATOCMS_API_TOKEN });
const itemId = "4235";
const item = await client.items.update(itemId, { // we just pass the field that we want to change title: "[EDIT] My first blog post!", });
console.log(item);}
run();
{ id: "hWl-mnkWRYmMCSTq4z_piQ", title: "My first blog post!", content: "Lorem ipsum dolor sit amet...", category: "24", image: { alt: "Alt text", title: "Image title", custom_data: {}, focal_point: null, upload_id: "20042921", }, meta: { created_at: "2020-04-21T07:57:11.124Z", updated_at: "2020-04-21T07:57:11.124Z", published_at: "2020-04-21T07:57:11.124Z", first_published_at: "2020-04-21T07:57:11.124Z", publication_scheduled_at: "2020-04-21T07:57:11.124Z", unpublishing_scheduled_at: "2020-04-21T07:57:11.124Z", status: "published", is_current_version_valid: true, is_published_version_valid: true, current_version: "4234", stage: null, has_children: true, }, item_type: { type: "item_type", id: "DxMaW10UQiCmZcuuA-IkkA" },}
The following sections highlight the rules and strategies that are specific to the update process.
As with creation, you cannot edit blocks directly; you must update the parent record that contains them. The payload you send uses a mix of block IDs and block objects to define the desired final state.
The rules for adding, updating, keeping, deleting, and reordering blocks are covered in detail in the main records guide.
➡️ See the complete guide to Creating and Updating Blocks
When updating a block, you use destructuring to combine existing and updated content. Use Array.map()
to go through the existing blocks one by one, keeping their current ordering.
import { buildClient } from "@datocms/cma-client-node";
async function run() { // Make sure the API token has access to the CMA, and is stored securely const client = buildClient({ apiToken: process.env.DATOCMS_API_TOKEN });
// These define what to update const recordId = "A4gkL_8pTZmcyJ-IlIEd2w"; // The record's unique ID const fieldWithBlocks = "modular_content_field"; // Which record field are the blocks in? const blockId = "ToBApjdYQaCgeFJxp_ty0A"; // ID of the block we want to update ("Example block #1") const blockFieldsToUpdate = { // Inside the block, what are we updating? title: "Example block #1 (Updated title)", // Update the title };
// Get the current record const currentRecord = await client.items.find(recordId, { nested: true, // Also fetch the content of nested blocks, not just their IDs });
console.log( "Current record before the update, with nested blocks", JSON.stringify(currentRecord, null, 2), );
// Build the update before sending it const currentBlock = currentRecord[fieldWithBlocks].find( (block) => block.id === blockId, ); // The block's existing content const updatedBlock = { ...currentBlock, // Keep its existing metadata attributes: { ...currentBlock.attributes, // Keep existing attributes that we didn't update ...blockFieldsToUpdate, // Inject updated fields }, }; const updatedFieldWithBlocks = currentRecord[fieldWithBlocks].map( ( block, // Map through existing blocks so we keep their ordering ) => block.id === updatedBlock.id ? updatedBlock // If it's the block we want to update, inject the updated data : block.id, // Otherwise, just provide the old block's ID and the API will know to keep it unchanged );
// Perform the update by actually sending what we built to the API const updatedRecord = await client.items.update(recordId, { [fieldWithBlocks]: updatedFieldWithBlocks, // The record field to update // We don't have to specify the other fields. The API will keep them the same. });
console.log( "Updated record. Only block IDs are returned, not their content.", updatedRecord, );}
run();
// Current record before the update, with nested blocks{ id: "A4gkL_8pTZmcyJ-IlIEd2w", type: "item", title: "This is an example record with blocks in a modular content field", modular_content_field: [ { type: "item", attributes: { title: "Example block #1", }, relationships: { item_type: { data: { id: "cR-9e-65SNat84KEs5M22w", type: "item_type", }, }, }, id: "ToBApjdYQaCgeFJxp_ty0A", }, { type: "item", attributes: { title: "Example block #2", }, relationships: { item_type: { data: { id: "cR-9e-65SNat84KEs5M22w", type: "item_type", }, }, }, id: "YGrrPYrkSNaq-dBaP7aSaQ", }, ], item_type: { id: "LvTZuGYRTQO9aBVk0g35Jw", type: "item_type", }, creator: { id: "627975", type: "organization", }, meta: { created_at: "2024-09-06T17:19:59.151+01:00", updated_at: "2024-10-03T00:41:15.497+01:00", published_at: "2024-10-03T00:41:15.538+01:00", publication_scheduled_at: null, unpublishing_scheduled_at: null, first_published_at: "2024-09-06T17:19:59.215+01:00", is_valid: true, is_current_version_valid: true, is_published_version_valid: true, status: "published", current_version: "EFYp72wJQf24L_jL1C1_tw", stage: null, },}
/* Updated record. Only block IDs are returned, not their content.{ id: 'A4gkL_8pTZmcyJ-IlIEd2w', type: 'item', title: 'This is an example record with blocks in a modular content field', modular_content_field: [ 'ToBApjdYQaCgeFJxp_ty0A', 'YGrrPYrkSNaq-dBaP7aSaQ' ], item_type: { id: 'LvTZuGYRTQO9aBVk0g35Jw', type: 'item_type' }, creator: { id: '627975', type: 'organization' }, meta: { created_at: '2024-09-06T17:19:59.151+01:00', updated_at: '2024-10-03T00:41:21.730+01:00', published_at: '2024-10-03T00:41:21.784+01:00', publication_scheduled_at: null, unpublishing_scheduled_at: null, first_published_at: '2024-09-06T17:19:59.215+01:00', is_valid: true, is_current_version_valid: true, is_published_version_valid: true, status: 'published', current_version: 'Af6ykuN7S6WGMcwD3XZUdQ', stage: null }}*/
You can reorder block records by changing their IDs position in the modular content field array.
import { buildClient } from "@datocms/cma-client-node";
async function run() { // Make sure the API token has access to the CMA, and is stored securely const client = buildClient({ apiToken: process.env.DATOCMS_API_TOKEN });
const itemId = "4235"; const item = await client.items.update(itemId, { // previous order was ['565346546', '565346547', '565346548'] content: ["565346548", "565346547", "565346546"], });
console.log(item);}
run();
const result = { type: "item", id: "4235", title: "Title", content: ["565346548", "565346547", "565346546"], meta: { /* ... */ }, item_type: { type: "item_type", id: "44" }, creator: { type: "access_token", id: "312" },};
In this case, you must not pass an ID to buildBlockRecord
.
It's not required the presence of all the fields in the payload. If it's easier for you to include all of them, just pass null
, as it's a valid value for every field type.
When a field is not present in the payload, or its value is null
, then the field's default value will be used (if available).
import { buildClient, buildBlockRecord } from "@datocms/cma-client-node";
async function run() { // Make sure the API token has access to the CMA, and is stored securely const client = buildClient({ apiToken: process.env.DATOCMS_API_TOKEN });
const itemId = "4235"; const item = await client.items.update(itemId, { // previous order was ['565346546', '565346547', '565346548'] content: ["565346548", "565346547", "565346546"], });
console.log(item);}
run();
async function run() { // Make sure the API token has access to the CMA, and is stored securely const client = buildClient({ apiToken: process.env.DATOCMS_API_TOKEN });
const itemId = "4235"; const blockModelId = "23455234";
const item = await client.items.update(itemId, { content: [ // new block record: buildBlockRecord({ item_type: { type: "item_type", id: blockModelId }, text: "new block record text", subtext: "another text", }), // existing block record IDs: "565346546", "565346547", "565346548", ], });
console.log(item);}
run();
const result = { type: "item", id: "4235", title: "Title", // block '565346549' has been added: content: ["565346549", "565346546", "565346547", "565346548"], meta: { /* ... */ }, item_type: { type: "item_type", id: "44" }, creator: { type: "access_token", id: "312" },};
To delete a block record, remove its ID from the modular content field array.
import { buildClient } from "@datocms/cma-client-node";
async function run() { // Make sure the API token has access to the CMA, and is stored securely const client = buildClient({ apiToken: process.env.DATOCMS_API_TOKEN });
const itemId = "4235";
const item = await client.items.update(itemId, { // previous value was ['565346546', '565346547', '565346548'], let's remove '565346547' content: ["565346546", "565346548"], });
console.log(item);}
run();
const result = { type: "item", id: "4235", title: "Title", // block '565346547' has been removed! content: ["565346546", "565346548"], meta: { /* ... */ }, item_type: { type: "item_type", id: "44" }, creator: { type: "access_token", id: "312" },};
➡️ Before proceeding, ensure you have read the general guide on Localization
When you send an update request, the API follows these strict rules.
When you update a translated field, you must provide the entire object for that field, including all the languages you want to keep unchanged. You can't just send the one language you're changing.
{ "title": { "en": "Hello World", "it": "Ciao a tutti! (Updated)" }}
This is the only time you can't just send the one field you're changing. To add or remove a language from an entire record, you must include all translated fields in your request. This is to enforce the Locale Sync Rule and ensure all fields remain consistent.
title
and content
, your request must include both fields with the new fr
locale.If your API key only has permission for certain languages (e.g., only English), you must only include those languages in your update. The system is smart and will automatically protect and preserve the content for the languages you can't access (like Italian or French).
This table shows what happens in different situations. The key takeaway is that your update payload defines the new final state for the languages you are allowed to manage.
Your Role manages | Record currently Has | Your payload sends | Result |
---|---|---|---|
English | English | English | ✅ English is updated. |
English, Italian | English | English, Italian | ✅ English is updated. ➕ Italian is added. |
English, Italian | English, Italian | English | ✅ English is updated. ➖ Italian is removed. |
English, Italian | English, Italian | English, Italian | ✅ English is updated. ✅ Italian is updated. |
Eng, Ita, Fre | English, Italian | English, French | ✅ English is updated. ➖ Italian is removed. ➕ French is added. |
English | English, Italian | English | ✅ English is updated. 🛡️ Italian is preserved. |
English, Italian | English, French | English, Italian | ✅ English is updated. 🛡️ French is preserved. ➕ Italian is added. |
English, Italian | English, French | Italian | ➖ English is removed. 🛡️ French is preserved. ➕ Italian is added. |
The rules about localization work in combination with the rules for updating blocks: you use full block objects to create/update and block IDs to leave unchanged, but you do so within the object for a specific locale.
This payload updates the title of an existing block in the en
locale, while leaving the second English block and all Italian blocks untouched. The it
locale needs to be included in the payload, or the Italian locale will be deleted!
{ "content_blocks": { "en": [ { "id": "dhVR2HqgRVCTGFi0bWqLqA", "type": "item", "attributes": { "title": "Updated English Title" } }, "kL9mN3pQrStUvWxYzAbCdE" ], "it": [ "dhVR2HqgRVCTGFi_0bWqLqA", "kL9mN3pQrStUvWxYzAbCdE" ] }}
This payload adds a new block to the it
locale only. The en
locale needs to be included in the payload, or the Italian locale will be deleted!
{ "content_blocks": { "en": [ "dhVR2HqgRVCTGFi_0bWqLqA", "kL9mN3pQrStUvWxYzAbCdE" ], "it": [ "fG8hI1jKlMnOpQrStUvWxY", { "type": "item", "attributes": { "title": "Nuovo Blocco" }, "relationships": { "item_type": { "data": { "id": "BxZ9Y2aKQVeTnM4hP8wLpD", "type": "item_type" } } } }, "dhVR2HqgRVCTGFi0bWqLqA" ] }}
To add a new locale to an existing record, you must provide values for all localized fields for that new locale, and include existing locales that you want to preserve.
{ "title": { "en": "English Title", "fr": "Titre Français", }, "content_blocks": { "en": [ "dhVR2HqgRVCTGFi_0bWqLqA", "kL9mN3pQrStUvWxYzAbCdE" ], "fr": [ { "type": "item", "attributes": { "title": "Nouveau Bloc Français" }, "relationships": { "item_type": { "data": { "id": "BxZ9Y2aKQVeTnM4hP8wLpD", "type": "item_type" } } } } ] }}
If the 'All locales required?' option in a model is turned off, then its records do not need all environment's locales to be defined for localized fields, so you're free to add/remove locales during an update operation.
Suppose your environment's locales are English, Italian and German (['en', 'it', 'de']
) and the following record currently defines en
and it
locales on its localized fields (title
and content
):
const item = { id: '4235', // localized field title: { en: 'My title', it: 'Il mio titolo' }, // localized field content: { en: 'Article content', it: 'Contenuto articolo', }, // non-localized field votes_count: 10, meta: { /* ... */ }, item_type: { type: 'item_type', id: '44' }, creator: { type: 'access_token', id: '312' },}
To add the de
locale to this record, you have to send an update request containing all localized fields. For each one of these, you must define the exiting locales plus the ones you want to add:
import { buildClient } from "@datocms/cma-client-node";
async function run() { // Make sure the API token has access to the CMA, and is stored securely const client = buildClient({ apiToken: process.env.DATOCMS_API_TOKEN });
const itemId = "4235";
const item = await client.items.update(itemId, { title: { en: "My title", it: "Il mio titolo", de: "Mein Titel", }, content: { en: "Article content", it: "Contenuto articolo", de: "Artikelinhalt", }, });
console.log(item);}
run();
const result = { type: "item", id: "4235", title: { en: "My title", it: "Il mio titolo", de: "Mein Titel", }, content: { en: "Article content", it: "Contenuto dell'articolo", de: "Artikelinhalt", }, votes_count: 10, meta: { /* ... */ }, item_type: { type: "item_type", id: "44" }, creator: { type: "access_token", id: "312" },};
If the 'All locales required?' option in a model is turned off, then its records do not need all environment's locales to be defined for localized fields, so you're free to add/remove locales during an update operation.
Let's suppose your environment's locales are English (en
), Italian (it
) and German (de
) and the following record currently defines en
and it
locales on its localized fields (title
and content
):
const item = { id: '4235', // localized field title: { en: 'My title', it: 'Il mio titolo' }, // localized field content: { en: 'Article content', it: 'Contenuto articolo', }, // non-localized field votes_count: 10, meta: { /* ... */ }, item_type: { type: 'item_type', id: '44' }, creator: { type: 'access_token', id: '312' },}
To remove the it
locale from this record, you have to send an update request containing all localized fields. For each one fo these, you must define the exiting locales, except the ones you want to remove:
import { buildClient } from "@datocms/cma-client-node";
async function run() { // Make sure the API token has access to the CMA, and is stored securely const client = buildClient({ apiToken: process.env.DATOCMS_API_TOKEN });
const itemId = "4235"; const item = await client.items.update(itemId, { title: { en: "My title", }, content: { en: "Article content", }, });
console.log(item);}
run();
const result = { type: "item", id: "4235", title: { en: "My title", }, content: { en: "Article content", }, votes_count: 10, meta: { /* ... */ }, item_type: { type: "item_type", id: "44" }, creator: { type: "access_token", id: "312" },};
To prevent clients from accidentally overwriting each other's changes, the update endpoint supports optimistic locking. You can include the record's current version number in the meta
object of your payload.
If the version on the server is newer than the one you provide, the API will reject the update with a 422 STALE_ITEM_VERSION
error, indicating that the record has been modified since you last fetched it.
import { ApiError, buildClient } from "datocms-client";
// Make sure the API token has access to the CMA, and is stored securelyconst client = buildClient({ apiToken: process.env.DATOCMS_API_TOKEN });
async function updateRecordByIncrementingCounter(itemId) { // first we get the record we want to update const record = await client.items.find(itemId);
try { // now we increment the counter value, passing the current version // to enable optimistic-locking client.items.update(itemId, { counter: record.counter + 1, meta: { current_version: record.meta.current_version }, });
console.log("Done!"); } catch (e) { // if we get a STALE_ITEM_VERSION error, this means that the // the record changed in-between the find and update operations, so we have // to fetch the latest version of the record and try again if (e instanceof ApiError && e.findError("STALE_ITEM_VERSION")) { console.log("Stale version, retrying..."); return updateRecordByIncrementingCounter(); }
throw e; }}
await updateRecordByIncrementingCounter("1230982");
> node example.js
Stale version, retrying...Stale version, retrying...Done!
Date of creation
Date of first publication
The ID of the current record version (for optimistic locking, see the example)
"4234"
The new stage to move the record to
The entity (account/collaborator/access token/sso user) who created the record
Returns a resource object of type item