Feeding the AI Vampire: A CMS Migration [Part 1]

ChatGPT AI Vampire me

It’s been a while since I’ve been this deeply involved in writing code. Or, perhaps more accurately, orchestrating the writing of code. Over the last six weeks, alongside my regular responsibilities as Head of Engineering, I’ve been migrating our websites away from Contentful and Sanity to Payload CMS.

Two brands, three sites, ten languages, over 1,000 articles, FAQs, legal documents and branded “Sell With Us” pages. All migrated as what started out as a side project. A PoC that quickly snowballed into a full migration, a fair bit of refactoring, and an ever-growing list of ideas for what we could do next. (e.g. Side Quest 1)

It’s been a big lift and an awful lot of fun. It’s saved us over $40,000 a year, potentially more. And it’s made me reflect on Steve Yegge Vampire Post. More on that later, because I think I’ve been feeding one.

How did we get here?

Four or five years ago, we chose Contentful after reviewing the options on the market and establishing that it was the best fit for our needs. In those early days, we were building our “Glocal” platform, supporting multiple markets and languages, balancing global consistency with local requirements.

We were also learning. This was our first real experience of introducing a CMS into the platform, and with hindsight, some of the decisions we made reflected that. Over the following years, we watched from the sidelines as alternative providers became more feature-rich, less restrictive, and increasingly closer to the code.

Meanwhile, our relationship with Contentful became more difficult.

The arbitrary language and content model limits were restrictive, portability wasn’t great, and the analytics and visibility around usage left a lot to be desired. At one point, we received a large overage bill caused by a single image, with no meaningful way of seeing or anticipating the problem beforehand. Only post mortem after the event with customer service sending us manual exports of reports we weren’t allowed access to. Increasingly, it felt like we were putting square pegs into round holes.

Things finally came to a head this year. Our renewal was due in October, Salesforce had acquired Contentful, and we needed several additional features, including more languages. We were also approaching our content model limit. Accommodating those requirements would have pushed us into yet another pricing tier. The juice wasn’t worth the squeeze.

We had escape routes. We could move content into our caching middleware microservice or hardcode it directly into the pages. We’d already hardcoded some of the relatively static pages where changing a Next.js template was simpler than fighting the CMS. But neither was where we wanted to be. We wanted a CMS that worked for and with us, rather than one we constantly had to work around.

From Sanity to Payload

We’d already started exploring our options. An earlier PoC for our corporate site using Sanity had demonstrated its potential, and we’d engaged with an excellent agency to price up a wider migration.

I’d been following Sanity’s journey for several years and was genuinely excited about the prospect of adopting it more widely. In truth, I wanted to go with Sanity. Our experience building the corporate site had been great. However, with AI development tools progressing at the rate they are, and our platform so heavily invested in the Next.js ecosystem, Payload seemed worth investigating.

Cue a series of discussions with my architect buddy, Jean-Claude (Claude Opus 5.5 High), about the best fit for our requirements, how to approach a PoC, and what a migration might look like. “We” agreed that the next step was to trial self-hosting Payload. It offered a route away from Contentful without simply moving ourselves into another platform we might struggle to leave. We could own the hosting, keep control of our data and build something that fitted our existing architecture and ways of working.

Our DevOps wizard set it up while I was on holiday, so when I returned, I had an environment ready to experiment with. And what an environment. Built to his legendary standards, with APM, logging, and the ability to scale as our usage grew. From an infrastructure perspective, I was never in doubt about our/his ability to run it.

So I started what was supposed to be a PoC. Which rather quickly snowballed into migrating everything from Contentful. And, for good measure, moving what we’d already built in Sanity for thecollectinggroup.com as well. I hadn’t quite planned it that way…

A few architectural decisions

My original plan was to incorporate Payload into our main frontend repository. However, keeping it standalone has turned out to be the better decision. It fits comfortably alongside our existing architecture without adding to the build time of our busiest frontend repository. And importantly, it significantly reduces the blast radius. We can deploy and evolve the CMS independently, without dragging the main frontend application along for the ride. It also makes Payload even more portable. If we decide to change direction again in the future, we’ve kept our options open.

From day one, Payload has proven flexible and easy to work with. It feels much closer to how we want to build software, rather than a separate system we’re constantly having to accommodate.

Migrating without breaking the business

One of the biggest challenges was moving over 1,000 articles while keeping both Contentful and Payload running. I didn’t want a one-shot migration that left us scrambling to fix data or manually reproduce changes between the two systems. Instead, I scripted everything. The goal was to be able to synchronise Contentful and Payload repeatedly, reliably and with as little hassle as possible. That gave me the genuine option of using either system while I proved Payload worked.

It also meant I could migrate content, validate the results, make changes, and run the migration again without having to start from scratch. I used feature toggles to switch between Contentful and Payload. This was particularly satisfying. Being able to update articles programmatically, validate the results, and change the source of content gave me much more confidence in the migration.

For most of the other content, I took a more direct approach. The changes were relatively low risk, and the turnaround was quicker than adding the extra complexity of feature toggles. There was still the real deadline of our Contentful contract ending in October. And we run an auction platform. Breaking a page or causing disruption around an auction ending isn’t an acceptable trade-off for getting a CMS migration over the line. That meant being careful about when and how I released changes.

Thankfully, our deployment systems meant we could deploy and roll back reliably, as frequently as we needed. The option of falling back to hardcoded content or our caching middleware was always there too. But those were escape routes, not the outcome we wanted. The migration was unproven until it was proven. With a hard deadline looming, that was an interesting position to be in.

I’ve also got to thank the team for putting up with a variety of PRs across the codebase. This wasn’t a neat little change contained within one repository.

Feeding the AI Vampire

Steve Yegge wrote about something he called The AI Vampire earlier this year. The idea resonated with me more than I’d like to admit. During this migration, I felt alive. Productive. I was having an enormous amount of fun. And I got hooked. I found myself burning the candle at both ends. Up early, working through the migration before the day started, and releasing late in the evening.

There were practical reasons for this. Early mornings and late evenings were quieter periods, outside our busiest auction windows, which reduced the risk of releasing larger changes. They also happened to be the times when nobody else was online needing me for something. I could focus 100% on the migration.

I broke the work down into a series of epics, spikes and tasks, using Claude and Cursor to help plan, manage and deliver the work. Everything had a place, and I could move between problems without losing track of the wider migration.

Every time I solved a problem, I could see the next one. Every time I finished a piece of work, I thought of another improvement. With AI removing so much of the friction between having an idea and getting something working, it was incredibly tempting to keep going.

The deadline certainly added pressure. There was a commercial consequence to missing it, and despite all the progress, the migration wasn’t finished until it was finished.

But it would be disingenuous to blame the deadline entirely. I was enjoying myself. Perhaps a little too much. I’ve spent a lot of time thinking about AI adoption from a leadership perspective. The guardrails, expectations, coaching and engineering systems needed to make it successful. This experience reminded me that I need to apply more of those lessons to myself. Being able to do more doesn’t necessarily mean I should keep doing more.

Back on the tools

One of the unexpected benefits of this migration has been getting properly back on the tools. In an Engineering Leadership position, it’s easy to become increasingly removed from the day-to-day experience of writing and shipping software. You’re involved in the decisions, the architecture, the priorities and the problems, but you’re not necessarily the person experiencing all the friction.

Spending six weeks working across our codebase has brought me much closer to what the team are dealing with. I’ve experienced the frustrations, found friction points, and had the opportunity to address some of them directly. Whether that’s fixing things in the code, refactoring areas that could be better, or experimenting with different ways of working. It’s also given me more credibility when suggesting technical changes. There’s a difference between recommending something from the sidelines and having tried it yourself, encountered the problems, and worked through them.

I’ve really enjoyed that. Long may it continue.

But balancing building and managing hasn’t been easy. During the more stressful parts of the migration, particularly moving over 1,000 articles and proving that Payload could do everything we needed, I definitely focused too much on building and not enough on managing. The combination of a hard deadline, uncertainty and the enjoyment of making progress made it all too easy to disappear into the work. I’m grateful for the team’s patience.

Going forward, I want to regain some of those boundaries (and some sleep), while finding a better balance between building and leading. Part of that is continuing to delegate more. I’ve been increasingly using GrokBot to handle repeatable tasks, freeing up more of my time for both engineering and management.

I don’t want to return to being a full-time individual contributor, but nor do I want to retreat from the code again. Staying technically involved has already made me a better-informed leader. The challenge is making that sustainable without neglecting the other responsibilities that come with the role.

That’s all a work in progress.

Leave a Reply