[{"data":1,"prerenderedAt":285},["ShallowReactive",2],{"DefaultLayouten":3,"language-blog-slug-scripted-cms-migrations-i18n-slugs":134,"language-blog-slug-en-scripted-cms-migrations":138},{"app":4,"menu":31,"footer":66},{"githubUrl":5,"youtubeUrl":6,"linkedinUrl":7,"phoneNumber":8,"emailAddress":9,"legal":10,"addresses":20},"https:\u002F\u002Fgithub.com\u002Fvoorhoede\u002F","https:\u002F\u002Fwww.youtube.com\u002Fchannel\u002FUCzHuhQVYFRixtQN2-swcuGg","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fde-voorhoede","+31 20 2610 954","post@voorhoede.nl",[11,14,17],{"title":12,"value":13},"KvK","56017235",{"title":15,"value":16},"BTW","NL851944620B01",{"title":18,"value":19},"IBAN","NL14TRIO0320142078",[21,26],{"address":22,"city":23,"googleMapsLink":24,"postalCode":25},"Koivistokade 70","Amsterdam","https:\u002F\u002Fwww.google.com\u002Fmaps\u002Fplace\u002FDe+Voorhoede+%7C+Front-end+Development\u002F@52.396847,4.8700823,17z\u002Fdata=!3m1!4b1!4m5!3m4!1s0x47c5e21d502d2d59:0xbf570944a96ebf45!8m2!3d52.347647!4d4.8502154","1013 BB",{"address":27,"city":28,"googleMapsLink":29,"postalCode":30},"Koornmarkt 22","Delft","https:\u002F\u002Fwww.google.nl\u002Fmaps\u002Fplace\u002FKoornmarkt+22,+2611+EG+Delft\u002F@52.0093477,4.3573054,17z\u002F","2611 EG",{"title":32,"callToActions":33,"links":39},"Site Menu",[34],{"id":35,"title":36,"link":37},"163140902","Contact",{"__typename":38},"ContactRecord",[40,46,51,56,61],{"id":41,"title":42,"link":43},"163140904","Impact",{"__typename":44,"slug":45},"PageRecord","impact",{"id":47,"title":48,"link":49},"163140905","Services",{"__typename":50},"ServiceOverviewRecord",{"id":52,"title":53,"link":54},"163140906","Cases",{"__typename":55},"CaseOverviewRecord",{"id":57,"title":58,"link":59},"163140908","About us",{"__typename":44,"slug":60},"about-us",{"id":62,"title":63,"link":64},"d6WdFJq2SOuc3dWtpibbXQ","Work at",{"__typename":44,"slug":65},"work-at",{"links":67,"copyrightTitle":93,"copyrightLabel":94,"copyrightLink":95,"privacyTitle":96,"privacyLabel":97,"privacyLink":98,"certificatesGrid":99},[68,71,74,77,82,85,88],{"id":69,"title":42,"link":70},"144185264",{"__typename":44,"slug":45},{"id":72,"title":48,"link":73},"144185265",{"__typename":50},{"id":75,"title":53,"link":76},"144185266",{"__typename":55},{"id":78,"title":79,"link":80},"144185267","Blog",{"__typename":81},"BlogPostOverviewRecord",{"id":83,"title":58,"link":84},"144185268",{"__typename":44,"slug":60},{"id":86,"title":36,"link":87},"144185269",{"__typename":38},{"id":89,"title":90,"link":91},"144185270","FAQ",{"__typename":44,"slug":92},"faq","Creative Commons licence and disclaimer","CC BY 4.0","https:\u002F\u002Fcreativecommons.org\u002Flicenses\u002Fby\u002F4.0\u002F","De Voorhoede privacy statement (pdf)","Privacy statement","https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1763455455-vh-isms-006-privacy-statement-de-voorhoede-en.pdf",[100,112,123],{"id":101,"image":102,"link":107},"Xq4bBfg_TZ6Fkjax9mkbLQ",{"url":103,"alt":104,"width":105,"height":106},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687353463-b-corp-logo-black-rgb.png","B Corp logo",404,680,{"__typename":108,"id":109,"title":110,"url":111},"ExternalLinkRecord","fGW1ak8XQYaYDLkBSyncog","B Corp","https:\u002F\u002Fwww.bcorporation.net\u002Fen-us\u002Ffind-a-b-corp\u002Fcompany\u002Fde-voorhoede\u002F",{"id":113,"image":114,"link":119},"c5mCXRTiSraRIB25fw1p7Q",{"url":115,"alt":116,"width":117,"height":118},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687353461-dda-boxlogo-black.png","Dutch Digital Agencies logo",627,480,{"__typename":108,"id":120,"title":121,"url":122},"P6Jh7B0cTv2cKyNEeKVWVQ","Dutch Digital Agencies","https:\u002F\u002Fdutchdigitalagencies.com\u002Fleden\u002Fde-voorhoede\u002F",{"id":124,"image":125,"link":129},"MT5SCyNxSTSr_v5eeATMZw",{"url":126,"alt":127,"width":128,"height":128},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1775730283-dnv.png","DNV logo",518,{"id":130,"title":131,"link":132},"BRtNB5HnT5i-7HkA8IYzBw","DIV",{"__typename":44,"slug":133},"impact\u002Fdigitale-producten-privacy-by-design",[135],{"locale":136,"value":137},"en","scripted-cms-migrations",{"page":139},{"slug":137,"i18nSlugs":140,"social":142,"title":147,"subtitle":79,"isArchived":148,"headerIllustration":149,"date":154,"authors":155,"introTitle":164,"items":165,"pivots":242,"relatedBlogPosts":243,"tags":244,"onMountedScript":178,"onUnmountedScript":178},[141],{"locale":136,"value":137},{"title":143,"description":144,"image":145},"Safe CMS migrations with Scripted Migrations | De Voorhoede","Updating your content models manually is risky and inconvenient. You can update the wrong field or even remove it. Scripted migrations are here to save you.",{"url":146},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1669363496-linkedin-blog-alternatief.png","Safe and convenient CMS migrations with scripted migrations and sandbox environments",false,{"url":150,"alt":151,"width":152,"height":153},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1669362627-migration.svg",null,492,651,"2022-11-25T01:00:00.000+01:00",[156],{"name":157,"lastName":158,"slug":159,"image":160},"Frank","Warnaar","frank",{"url":161,"alt":151,"width":162,"height":163},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683534610-frank.jpg",2049,2732,"Updating your content models manually is risky and inconvenient. You can accidentally update the wrong field, or even remove it. Not only freaking out your content managers, but also yourself, as you’ll be working on damage control for the next few hours. Worry no more. Scripted migrations are here to save you.",[166,171,175,179,189,192,200,203,207,212,215,219,223,227,231,235,238],{"__typename":167,"id":168,"title":169,"body":170},"TextSectionRecord","143646827","Problems with manual content model changes","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Let&rsquo;s step back and look at the problems with changing content models manually. At De Voorhoede we usually work with DatoCMS. DatoCMS only supports scripted migrations recently. Until then, we used to run into problems having our content models get out of sync with our code until merging and deploying the code changes.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":167,"id":172,"title":173,"body":174},"143646828","Adding fields","\u003Cp>\u003Cspan style=\"font-weight: 400;\">For example, imagine you&rsquo;re working on a feature to add a new field to add a body text to a component. You add a new field to that component&rsquo;s model. However, while you&rsquo;re still working on the feature, the field is already available for content managers. But until the code to use that field is merged and deployed, the field doesn&rsquo;t do anything on production. This is confusing.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":167,"id":176,"title":177,"body":178},"143646829","Removing or renaming fields","",{"__typename":180,"id":181,"image":182,"caption":187,"fullWidth":148,"captionPosition":188},"ImageRecord","143646830",{"url":183,"alt":184,"width":185,"height":186},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1669131212-artboard.jpg","Removing a button on the page and also the field in the CMS",939,565,"How would it work to remove this button from the page and therefore also remove the field in the CMS?","bottom",{"__typename":167,"id":190,"title":178,"body":191},"143646831","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Adding new fields is actually the least of your problems. Removing or renaming fields is more painful. Fields can only be removed or renamed once they are not used anymore in the code. Otherwise your query will simply fail. Therefore, you end up only deleting fields once the code is merged and released to not use the old fields anymore. But by this time you have probably forgotten which field should be deleted.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":180,"id":193,"image":194,"caption":199,"fullWidth":148,"captionPosition":188},"143646832",{"url":195,"alt":196,"width":197,"height":198},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1669131259-3-cgngxh-jvocgfikqexzqx7bm5ortkodtzramblhcysmrmegvlp2270suk0qgyjv-jg9qscdi60uxh6cgxnoiir6ajvzyzqst9mdkfcnnmdnkazdcoholbmfwruuizlka1aeoaw6v4azwcy4kccnzakr8cpcgs0zs7xpot3yjjb-e5m7lauhxptiw7gvq.png","Delete field error message in Dato",699,250,"How you would delete a field manually",{"__typename":167,"id":201,"title":178,"body":202},"143646833","\u003Cp>\u003Cspan style=\"font-weight: 400;\">You can imagine this will one day end with production broken, you adding the field again, to find out the content of the records having this field filled in previously is now gone. Or you&rsquo;re afraid of deleting the incorrect field, breaking production and therefore don&rsquo;t delete it at all. This will become messy over time.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":167,"id":204,"title":205,"body":206},"143646834","Scripted migrations to the rescue!","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Scripted migrations solve those issues. They are like recipes for a CMS, containing all the steps needed to get from the previous state to the new content model structure. The scripts are stored in your codebase, so now your content modeling is tightly coupled with your code change.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">For instance, a migration script for the removal of a field would look like this:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":208,"id":209,"language":210,"body":211},"CodeBlockRecord","143646835","javascript","\u002F\u002F migrations\u002F1669119024_removeField.ts\nimport { Client } from ‘@datocms\u002Fcli\u002Flib\u002Fcma-client-node’;\n\nexport default async function (client: Client) {\n  await client.fields.destroy('home::cases_overview_page_link_label');\n}",{"__typename":167,"id":213,"title":178,"body":214},"143646836","\u003Cp>\u003Cspan style=\"font-weight: 400;\">On top of that, sandbox environments, which are supported by both DatoCMS and Contentful, provide a nice way to test out content model changes and migration scripts during development. Content modeling is hard. And therefore being able to test content model changes in isolation is huge!\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":167,"id":216,"title":217,"body":218},"143646837","Sandboxes for preview deployments","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Sandboxes are also useful for preview deployments. You can use a rule in your team to use your branch name for your sandbox environment (with `\u002F` replaced by `-`, as slashes are not supported by DatoCMS). Since your branch name is available in about every CI tool, you can now easily run preview deployments on pull requests using the new migration scripts from that pull request in isolation.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":167,"id":220,"title":221,"body":222},"143646838","Going to production","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Once a pull request gets merged, it&rsquo;s time to get the content model changes on the primary environment.&nbsp;\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">You could promote the sandbox you just created for the preview deployment. However, I don&rsquo;t recommend this. After you created that sandbox, another pull request might have been merged. This pull request could contain migrations that are not yet applied on your sandbox. Therefore it&rsquo;s best to always run the migrations on a fresh sandbox environment, based on your primary environment.&nbsp;\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">For clarity I recommend to use the version number of your code for environments created for production. Another tip is to keep the previous environment around after a production deployment. This way you can easily recover from disaster.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":167,"id":224,"title":225,"body":226},"143646839","Full backup capabilities","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Recovering from disaster also gets much more reliable for long term recovery when using scripted migrations.&nbsp;\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">Often we set up daily backups for DatoCMS, exporting all the contents as JSON to an S3 bucket. But without scripted migrations, you still don&rsquo;t have the history of your content models. So if something has gone wrong a month ago, you have all the content from then, but it&rsquo;s pretty useless. Because since then, your content models have changed. Now your backed up content doesn&rsquo;t match your models anymore, leaving you still unable to recover.&nbsp;\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">With scripted migrations you can recover your content models up to that point, as you can spin up a new CMS instance and run the migrations created until a month ago. Now, your content backup is in sync with your content models!\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":167,"id":228,"title":229,"body":230},"143646840","Generated migrations","\u003Cp>\u003Cspan style=\"font-weight: 400;\">The biggest downside of scripted migrations was that it was time consuming to write scripted migrations. Luckily, that&rsquo;s now in the past, since \u003C\u002Fspan>\u003Ca href=\"https:\u002F\u002Fwww.datocms.com\u002Fblog\u002Fintroducing-automatic-migrations-between-environments\">\u003Cspan style=\"font-weight: 400;\">DatoCMS can generate migration scripts\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"font-weight: 400;\"> for you:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":208,"id":232,"language":233,"body":234},"143646841","bash","npx @datocms\u002Fcli migrations:new '\u003Cname of migration>’ --autogenerate=\u003Cenvironment name to check diff for to main environment>",{"__typename":167,"id":236,"title":178,"body":237},"143646842","\u003Cp>\u003Cspan style=\"font-weight: 400;\">That&rsquo;s it for now! Happy content modeling!\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":167,"id":239,"title":240,"body":241},"143701784","You might also like","\u003Cul>\n  \u003Cli>\u003Ca href=\"https:\u002F\u002Fwww.voorhoede.nl\u002Fen\u002Fblog\u002Fupgrade-your-dato-cms-experience-with-custom-plugins\u002F\" title=\"Upgrade your (Dato)CMS experience with custom plugins\">Upgrade your (Dato)CMS experience with custom plugins\u003C\u002Fa> \u003Ca href=\"https:\u002F\u002Fwww.voorhoede.nl\u002Fen\u002Fblog\u002Fupgrade-your-dato-cms-experience-with-custom-plugins\u002F\" title=\"Upgrade your (Dato)CMS experience with custom plugins\"> \u003C\u002Fa>\u003C\u002Fli>\n  \u003Cli>\u003Ca href=\"https:\u002F\u002Fwww.voorhoede.nl\u002Fen\u002Fblog\u002Fenriching-rich-text-with-inline-components-datocms-react\u002F\" title=\"Enriching rich text with inline components (DatoCMS + React)\">Enriching rich text with inline components (DatoCMS + React)\u003C\u002Fa> \u003Ca href=\"https:\u002F\u002Fwww.voorhoede.nl\u002Fen\u002Fblog\u002Fenriching-rich-text-with-inline-components-datocms-react\u002F\" title=\"Enriching rich text with inline components (DatoCMS + React)\"> \u003C\u002Fa>\u003C\u002Fli>\n\u003C\u002Ful>",[],[],[245],{"id":246,"title":247,"slug":248,"blogPosts":249},"WTPJX79URE-O5lpWLJeEHg","Headless CMS","headless-cms",[250,261,278],{"slug":251,"title":252,"date":253,"authors":254},"dropbox-paper-as-a-headless-cms","Dropbox Paper as a headless CMS","2019-01-25T01:00:00.000+01:00",[255],{"name":256,"image":257},"Jasper",{"url":258,"alt":151,"width":259,"height":260},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683535518-jasper.jpg",1892,2523,{"slug":262,"title":263,"date":264,"authors":265},"figma-as-a-cms-where-design-and-development-collide","Figma as a CMS; where design and development collide","2022-02-10T01:00:00.000+01:00",[266,272],{"name":267,"image":268},"Bas ",{"url":269,"alt":151,"width":270,"height":271},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683535728-bas-g.jpg",2394,3192,{"name":273,"image":274},"Friso",{"url":275,"alt":151,"width":276,"height":277},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683534636-placeholder.jpg",1235,1646,{"slug":279,"title":280,"date":281,"authors":282},"enriching-rich-text-with-inline-components-datocms-react","Enriching rich text with inline components (DatoCMS + React)","2021-11-19T01:00:00.000+01:00",[283],{"name":256,"image":284},{"url":258,"alt":151,"width":259,"height":260},1776256149584]