We migrated all of ona.com content from CMS to local MDX files in 6 hours
I migrated ona.com from Sanity CMS to raw code and Markdown. I thought it would take 2-3 weeks. It took 6 hours, a few dollars in OCU (Ona Compute Units), and I never opened my IDE.
We introduced Sanity in September 2025 when we launched our rebrand. Even then, we weren't sure if a CMS was the right call - but it was the safe choice. A few months later, once we started using Ona for everything else, the CMS became the bottleneck. I couldn't tell Ona 'update the pricing page' because the content was locked behind an API. The agent could modify code, but it couldn't click through a GUI.
So I decided to migrate everything to code.
I started with a simple prompt:
Migrate all content from Sanity to local MDX and TypeScript files. Download all images. Update all pages to use local content loaders instead of Sanity queries.
Then I went to a meeting.
When I came back, Ona had written a migration script. It was using our Sanity API token to export content, converting documents to MDX with frontmatter, and downloading images. The script had already run and created about 60 files.
There were problems. The frontmatter format wasn't quite right. Some images were missing. The content loaders were throwing type errors.
I described each issue in chat. 'The event cards aren't showing the speaker photos.' Fixed. 'The blog post dates are in the wrong format.' Fixed. 'This video embed is broken.' Fixed.
I didn't debug anything. I didn't read stack traces. I just described what I saw and let the agent figure out the implementation.
Over 6 hours, here's what got done:
| What | Count |
|---|---|
| Files changed | 850+ |
| Images migrated | 533 |
| MDX content files created | 106 |
| TypeScript configs created | 26 |
| Sanity files deleted | 100+ |
| Sanity packages removed | 11 |
| IDE sessions opened | 0 |
| Human review time | ~3 hours |
The agent:
If I'd done this myself, I would have spent the first few days just writing specs: inventory all content types, map Sanity schemas to MDX frontmatter, document every edge case upfront. Then write migration scripts, run them, debug failures, run again.
With an agent, I skipped the spec phase entirely. I described the goal, let Ona take a first pass, and fixed issues as they surfaced. Some problems I never would have anticipated in a spec - they only became visible when the migration ran.
Here's what we ran into:
Schema mismatches: Sanity's flexible schema meant content had evolved organically over time. Some blog posts had author as a string, others as a reference, others as an array of references. Ona ran multiple passes to normalize everything into a consistent format.
Rich text conversion: Sanity stores rich text as Portable Text - a deeply nested JSON structure. Converting this to clean MDX while preserving links, code blocks, and custom components required careful handling. Some edge cases (nested lists inside blockquotes) needed manual review.
Image optimization pipeline: We had 533 images, but they weren't just static files - Sanity was doing on-the-fly transformations (resizing, format conversion, cropping). We had to decide: download originals and rebuild the optimization pipeline, or download pre-transformed versions and accept the current sizes. We went with originals and added Next.js Image optimization.
Broken references: Some Sanity documents referenced other documents that had been deleted or were in draft state. The migration script would fail silently on these. We added validation to catch orphaned references and either fix them or remove them.
URL structure changes: Some content had defined its own slugs in Sanity, others auto-generated them. A few had special characters or spaces that worked in Sanity but broke as file paths. We needed a slug normalization pass.
Video embeds: We had a mix of YouTube embeds and Mux-hosted videos. Each needed different handling in the new MDX format. Some videos were gated behind forms - that logic had to be preserved.
Incremental rollout: We couldn't do a big-bang cutover. The migration happened over multiple PRs while the site stayed live. This meant maintaining both code paths temporarily - pages that could read from either Sanity or local files depending on what had been migrated.
The best part of any migration is what you get to delete. Here's what's gone:
sanityFetch() calls scattered across the codebasesanity typegen every time the schema changedThe codebase is simpler. An agent can understand the entire content model by reading a few TypeScript files. No network requests, no API documentation, no authentication flows.
I could have done this migration myself. I've done CMS migrations before. Write scripts, run them, fix edge cases, run them again. Tedious, detail-oriented work.
I didn't want to spend two weeks on it. I had other things to do-shipping features, reviewing PRs.
So the migration happened in the background. Check in between meetings, describe issues, move on. The agent maintained context across sessions, remembered what we'd tried, kept making progress.
The creative decisions were still mine. The execution wasn't.
Our website is now entirely in code. Every page, every blog post, every event, every image-it's all in the repo.
Want to fix a typo? Push a commit. Want to add a blog post? Create an MDX file. Want to update the pricing page? Edit the TypeScript config.
Want an agent to do any of this? Ask. No CMS in the way.
The content is code. The code is the content. And agents can work with code.
If you're thinking about a similar migration-CMS to code, monolith to microservices, framework upgrade-the pattern is the same:
You don't need to understand every line of the migration script. You don't need to debug edge cases yourself. You need to know what 'done' looks like and describe when you're not there yet.
The new skill isn't writing migration scripts. It's describing outcomes.
This migration was done using Ona. The entire process happened through chat, with work executing in isolated cloud environments while I did other things.
Run migrations, refactors, and bulk changes in the background while you do other work
This website uses cookies to enhance the user experience. Read our cookie policy for more info.