Your team decides to migrate away from your headless CMS. Contract's up, pricing's gone sideways, or something better came along. Doesn't matter. You scope the work. One sprint, maybe two if the export tooling is janky. You've moved data before. This is just content.
Three months later, your engineers are still at it.
Headless CMS vendor lock-in rarely announces itself. It surfaces during the migration: the content model expressed in a proprietary format that doesn't translate to anything else, assets on the vendor's CDN with every URL in your database pointing to their domain, an export CLI that last saw a meaningful update two years ago and fails silently on large datasets, an API shape idiosyncratic enough that your new platform needs a bespoke transformation layer just to read the data.
You didn't buy software. You bought into a content architecture you don't control. And nobody lied to you. It was just never the thing that came up in the sales call.
It's not one thing. It stacks across four areas, and most teams only find out about all four at once, during a migration, when it's too late to scope properly.
Content model format. Your schema (field types, relationships, validations) is defined somewhere. The question is whether that definition means anything outside this specific platform. If it lives in a GUI that can only export to the vendor's own import format, you don't really have a content model. You have a vendor-specific configuration. You can't version control it, you can't hand it to another system, and you definitely can't diff it when something changes.
Asset URLs baked into content. This one is quiet until it isn't. When you upload an image through a managed CMS, it lands on their CDN. images.ctfassets.net. Something like that. And your rich text, your page data, your component fields: they all reference that URL. When you cancel your subscription, those URLs return 403s. The files aren't gone. But they're not on infrastructure you control, and every piece of content referencing them is now broken. Nobody talks about this one until they're staring at a spreadsheet of 4,000 dead image URLs at 11pm.
API shape. Sanity has GROQ. It's genuinely powerful. It's also a query language that exists solely within Sanity's ecosystem. Every hour you invest learning it doesn't transfer anywhere. Contentful has GraphQL support, but layered on top of its own REST conventions and filter syntax. The code you write against any of these APIs is coupled to that platform. Not "needs updating" when you leave. A rewrite.
What you actually get when you export. This is the real test. Run the export command on your current CMS right now and look at the output. Are relationships intact? Do assets have original filenames or are they UUIDs? Is the schema in there at all, or just the entries? Is version history included? These aren't edge cases. They're the things that blow up migration timelines. The cruelty is you won't find out until you actually try.
Every CMS terms of service says something like: "You own your content." True. No one is disputing that your words belong to you.
But ownership without portability is just a nice thing to say in a contract.
What portability actually means in practice:
A machine-readable schema export. Not a PDF of your content model. Not a list of field names in a support doc. A structured file, JSON or anything standard, that another system can actually read and act on. Something you can check into git. Something an engineer who's never opened your CMS can look at and understand.
Assets with original filenames. Not 3f8a92c1-b447-4d12-ae09-1f6c82940d75.jpg. Actual filenames. If your export hands you a folder of UUIDs, you still technically have your files. You just have no idea which ones go where without a mapping table that lives inside the vendor's database.
A way out that doesn't go through them. Here's the tell: if the documented migration path requires the vendor's own CLI, their own API, or a third-party service they've conveniently partnered with, that's not portability. That's a longer leash. Real portability means you can reconstruct your content architecture from the export alone, without their infrastructure needing to be running to do it.
Ownership is a precondition. It's not the thing itself.
Don't treat this as a features comparison. Treat it as a due diligence checklist. Get answers from the docs or by actually running the tools. Not from a demo.
1. Can I export my content model in a format another system can read? Run the export. Open it. Does the schema come with it, or just the entries? Can you take that output and rebuild your content structure somewhere else from scratch? If the answer is "you'd need to recreate the content types manually," you have your answer.
2. Where do my assets actually live, and what happens when I stop paying? Are uploads going to the vendor's CDN? What do the URLs look like? Can you configure the platform to use your own storage? This is not a hypothetical. It's the thing that turns two-week migrations into three-month ones.
3. Is the query interface a standard, or is it proprietary? GraphQL is a standard. REST is a standard. GROQ is not a standard. It's Sanity's thing. This matters less on day one and a lot more on day 400 when you're evaluating whether to stay.
4. Does the vendor document how to leave? Any platform documents how to import. The honest ones document how to migrate away. Go look for the outbound migration guide. If it doesn't exist, or the last commit was three years ago, you've learned something about how they think about the relationship.
5. What happens to your data if the company folds? The headless CMS space is not immune to consolidation, pivots, or shutdowns. If your data is sitting in a proprietary schema on infrastructure only they operate, what's the recovery plan? This should be a standard question in every vendor evaluation. It almost never is.
This isn't a cynical take. It's the same logic you apply everywhere else.
You don't write raw vendor-specific SQL into your application layer. You abstract behind an ORM because you might switch databases someday. You avoid hard dependencies on a single cloud provider's proprietary services when a portable alternative does the same job. Not because you're planning to leave. Because architecture that survives the decision to leave is just better architecture.
The same principle applies here. The CMS that earns long-term trust is the one built on the assumption that you might one day want out, and builds honestly anyway.
None of the lock-in vectors above are technically necessary. Portable schema formats aren't hard. Open storage integrations aren't novel. GraphQL is a standard anyone can implement. Export tooling that actually works is a choice. When a platform doesn't offer these things, that's a product decision, and it tells you something about whose interests the product was optimised for.
Mountain Labs was built with one assumption baked in from the start: you might want to take your content somewhere else someday. Standard GraphQL API, portable content model, export tooling that's a first-class feature rather than an afterthought. We think the CMS that respects your right to leave is the one worth staying with.
Not because we expect you to go. Because you should always be able to.
Mountain Labs is a headless CMS with a GraphQL API built for developers. Start your free 14-day trial →