We Turned the Technical Due Diligence Lens on Ourselves

Forge wasn't broken. Our ambitions had changed. After years of asking DD questions of other companies, we turned them on Beach and modernised the platform we want to build the next chapter on.

We Turned the Technical Due Diligence Lens on Ourselves

I've been involved in hundreds of technical due diligence exercises over the years. I've sat with founders and engineering teams and worked through the questions that inevitably surface when somebody starts looking seriously under the hood of a technology business. What runs the platform? What is end of life? Where are the security risks? Who has access to production? How repeatable are deployments? What happens if a key person disappears? How well tested is the system? Where does operational knowledge live? What would prevent this architecture supporting the next stage of growth?

They are reasonable questions, and when you spend enough time asking them of other companies, eventually you have to ask them of yourself. If Beach decided to raise investment for what we're building next, how would I feel putting our own technology through that process?

I knew the answer. We had some work to do.

Forge wasn't broken

That's an important place to start. Forge has been part of Beach for more than a decade. It has deployed and hosted huge numbers of sites and accumulated years of working product behaviour along the way. The problem wasn't that Forge had stopped working. In many ways, the opposite was true: it had kept working for a very long time, which is precisely how technology and infrastructure from an earlier period of a company's life can quietly become part of the furniture.

By 2025, the core application was still running Ruby 2.5 and Rails 5.2, both long out of support. Around it sat older dependencies, Cloud66 infrastructure, nginx configuration, bespoke certificate automation and operational processes that had evolved incrementally over many years. None of those things meant Forge was about to fall over, but together they represented a growing amount of operational and technical risk that we needed to understand properly.

Some of those dependencies had already become more than an inconvenience. In October 2025, an issue with our SSL infrastructure exposed just how tightly certificate generation had become coupled to historical infrastructure access. We resolved the immediate issue, but the more important finding was that a critical customer-facing capability had dependencies we simply weren't comfortable carrying forward.

If I had encountered the same thing during somebody else's technical DD, I knew exactly what I would have written.

The bigger reason to act

There was another, ultimately more important reason for doing this work. We have big plans for Gleo, and as those plans have developed, the role Forge plays underneath them has become increasingly important. Gleo.dev is about making it dramatically easier to build, deploy and grow modern web experiences, while Gleo.ai takes our ambitions further into productised services, playbooks and AI-assisted ways of working.

That changed the question we were asking of Forge. It was no longer simply whether we could continue operating it reliably. We needed to know whether this was the foundation we wanted to build the next generation of Beach products on.

Those are very different standards.

A system can be stable enough to continue operating while simultaneously being the wrong foundation for the next five or ten years of product development. We wanted Forge to become something we could confidently build on, rather than something we continually had to build around. We also knew that if outside investment ever became part of that next chapter, we didn't want a technical diligence process to be the event that finally forced us to confront problems we already understood.

For me, that is one of the more practical lessons from having spent so much time around DD: good technical due diligence starts long before the data room opens. If you already know the questions that are going to be asked, waiting for somebody else to ask them isn't much of a strategy.

Turning the lens inward

We had already started that process. An August 2025 technical assessment of Forge wasn't particularly comforting: we classified the migration as high risk and high complexity, with a recommended incremental modernisation approach and an estimated timeline of six to twelve months.

A Forge Platform canvas surrounded by the major areas under interrogation, with the question: would I be comfortable putting this in a data room?
Would I be comfortable putting this in a data room?

The assessment wasn't wrong. Forge contained around 35,000 lines of Ruby and years of battle-tested behaviour around deployments, billing, SSL, domains and customer accounts. Rewriting the application simply to get onto a more fashionable stack would have been a spectacular way to exchange known technical debt for unknown product bugs. When we revisited the problem in 2026, our conclusion on the core application was therefore explicit: refactor it incrementally rather than rewrite it.

Looking across the wider Forge stack, though, we realised we had been using the word legacy to describe systems that presented completely different kinds of problems. The Forge API was old, but contained enormous product value. Our Ruby CLI was old, but contained relatively little implementation that needed preserving. Our online compiler was old, but its biggest problem wasn't the version of Rails it ran; it was an execution model built around a shared sandbox. Ignite had accumulated infrastructure disproportionate to its current maintenance-mode usage, while our edge contained years of useful nginx behaviour alongside operational responsibilities, such as TLS, that we increasingly felt should belong to managed infrastructure.

Simply labelling all of that “technical debt” didn't help us decide what to do with it. We needed to understand where the value actually lived.

Modernisation doesn't mean rewriting everything

That became one of the principles behind the programme. Rather than starting with a preferred technical solution, we looked at what each part of the platform contained that was worth protecting. Sometimes that was source code and business logic. Sometimes it was an API contract, customer data or existing behaviour. In other places, there really wasn't enough value in the implementation to justify carrying it forward.

The core Forge application was the clearest example of preservation. In 2013, Forge's original product interface was an Ember.js app shipped with the Rails application. We replaced that interface in 2024, but the old code still lived in the stack and brought outdated dependencies that slowed things down. Once we removed it, the application was a much cleaner proposition: a JSON API, ActiveAdmin, authentication, background workers and a substantial amount of business logic that had been exercised in production for years. Rewriting that application would have put deploy, billing, SSL and domain behaviour at risk simply to address framework and dependency debt. So we kept the application and modernised underneath it.

The CLI received almost the opposite verdict. The old client was only a handful of Ruby files, with limited commands and an authentication and deployment model that no longer reflected where we wanted Forge to go. There wasn't enough valuable implementation to justify carrying it forward, particularly when the interface itself needed to change for developers, CI and increasingly AI agents. We rewrote it in TypeScript and Node instead.

Hammer Cloud, our remote build service, gave us a third answer. That is separate from Hammer for Mac, the local desktop builder we use to compile sites. The old hammer-manager ran customer builds through a shared filesystem and Docker sandbox, with a host/container arrangement and shared infrastructure that would still have existed even if we had successfully dragged its Ruby and Rails versions into the present day. We therefore preserved the contract Forge depended upon but replaced the machinery behind it. Hammer Cloud now separates orchestration from execution: Sidekiq coordinates the lifecycle of a build, while customer code executes in isolated, ephemeral jobs without access to Hammer's database or Redis.

Five Forge components with the value to preserve and the decision for each: refactor, rewrite, rebuild, replatform, rationalise.
Preserve the value. Change the rest. The right decision depends on where the value lives.

Same modernisation programme, three very different decisions. The useful lesson for us was that modernisation isn't synonymous with rewriting.

The job is to work out where the value lives, preserve that value, and change the things preventing it from carrying forward.

Making a big migration smaller

Another important shift was to stop thinking about Forge as one migration. The client, API, edge, build infrastructure and backend services were separate systems with contracts between them, and treating them that way gave us the opportunity to move them independently rather than orchestrating one enormous cutover.

Ignite could move without waiting for the main Forge API. Hammer Cloud could replace its execution infrastructure while preserving the existing completion contract back into Forge. The CLI could be rewritten while the API continued serving existing clients. The edge and API could be moved independently.

Instead of one migration with a single enormous blast radius, we had a series of smaller changes whose boundaries we could understand, test and, where necessary, reconsider.

Before and after: one coordinated Forge migration versus explicit contracts and independent migration paths.
Explicit contracts, independent paths, smaller blast radius.

That also made compatibility more important than architectural purity. During the Rails work, for example, existing JSON response shapes were explicitly treated as compatibility requirements. Root keys, nesting and serializer fields weren't to change without first auditing the clients that depended on them. There is nothing especially exciting about preserving a JSON response shape, but those sorts of decisions were fundamental to moving quickly without making every existing client part of the migration.

When six to twelve months became something very different

By July 2026, the situation was no longer the one we had assessed a year earlier. Ember was gone, we had a parallel Render environment, we could work against a real production database snapshot, and we had established a green RSpec baseline that could act as a gate as we moved through successive framework versions. We also knew where we wanted the infrastructure to land.

Those changes altered the risk equation considerably. During a weekend in late July, we took the core application from Ruby 2.5.1 and Rails 5.2.4 to Ruby 3.4.5 and Rails 8.0.5. We didn't jump from one end of that range to the other. We stepped through the major versions in the sequence laid out in the migration plan.

Timeline from a decade of accumulation through the 2025 high-risk assessment to the 2026 Rails upgrade and Render cutover.
Speed came from reducing uncertainty before trying to move quickly.

It would be easy, and misleading, to reduce that story to “a twelve-month migration took a weekend”. A lot had changed to make that weekend possible. The speed came from reducing uncertainty before trying to move quickly: establishing tests, simplifying the architecture, creating a parallel environment, understanding the client contracts and being very clear about the things we were deliberately not changing.

The way we build software with AI today unquestionably changed the economics too. It allowed us to work through dependency analysis, implementation, testing and documentation at a pace that would have been difficult to imagine when much of Forge was originally written.

AI didn't decide what should be preserved, make compatibility irrelevant, or remove the consequences of getting a production migration wrong. If anything, the ability to produce change faster puts more weight on engineering judgement, because it becomes very easy to change more than you should.

Moving where Forge runs

The Rails upgrade was only part of the work. A few weeks after, we completed the production cutover of the Forge API and forge-server to Render and stood down Cloud66.

Elsewhere in the stack, Ignite had already moved its remaining internal instances to Render and we'd removed both the old Cloud66 Parse stack and a sizeable AWS footprint behind Parse V2. Importantly, we didn't turn an infrastructure migration into an unnecessary data migration at the same time; the existing MongoDB databases remained in place. Hammer Cloud was establishing a path towards isolated, ephemeral builds, the new CLI was giving developers and agents a much more capable interface into the platform, and managed TLS removed an entire category of certificate infrastructure from our direct operational responsibilities.

Piece by piece, the shape of Forge was changing. The intention wasn't to make everything new. It was to reduce the amount of bespoke infrastructure and historical operational knowledge we needed to carry, while keeping the product behaviour and contracts that had proven their value.

Then, the day after the main production cutover, we got a useful reminder that those two things aren't always easy to separate.

Migration day isn't migration done

The next day, the new Render origin experienced a burst of traffic. Part of it was familiar internet background noise: WordPress and PHP scanners hitting random \*.getforge.io addresses. On the old infrastructure, nginx security rules rejected much of that traffic before it travelled any further. Our new Node edge didn't yet contain the equivalent behaviour, so requests that had previously disappeared quietly at the edge were suddenly reaching the origin.

We fixed the immediate problem, but I think the lesson is more interesting than the incident. When we talk about legacy systems, we tend to think about code, dependencies and infrastructure. A mature production system also accumulates behaviour, some of it deliberate and well documented, some captured in tests or configuration, and some that has simply been quietly doing useful work for years.

You don't always discover which is which until you remove it.

That is one reason I'm reluctant to describe a platform like Forge as simply “modernised”, as though there is a point at which the work is complete.

What we have now is a system we understand considerably better, with fewer hidden dependencies, clearer boundaries and foundations that are much closer to where we want to take the business.

Ready for what comes next

We haven't eliminated technical debt, and I don't think eliminating technical debt is a particularly useful objective. There are still things we want to improve, and some parts of the programme are deliberately unfinished. Ignite's infrastructure is modernised, for example, but we haven't relaunched it as a generally available billed product. Hammer Cloud continues to evolve, the CLI is moving towards increasingly agent-native workflows, and we'll keep hardening the edge as real production behaviour teaches us more.

What has changed is the conversation. A year ago, a meaningful part of our technology thinking was occupied by how we could safely move away from decisions made during previous eras of Forge. Increasingly, we're talking instead about what those foundations now allow us to build.

For me, that is the more meaningful measure of the work. If Beach eventually decides to raise capital around our ambitions for Gleo and the wider platform, I'm considerably more comfortable with the questions a technical diligence team would ask us. Not because everything is new, but because we can explain what we have, why we have it, what we've chosen to preserve, what we've replaced, what risks remain and what we're doing about them.

Having spent years asking those questions of other technology companies, that feels like a reasonable standard to hold ourselves to.

There is also an outcome we didn't necessarily anticipate at the start. As we've looked back over the programme, the process itself has become something worth preserving: how we assessed the existing platform, connected modernisation to future business requirements, identified where the value lived, chose between refactoring and rebuilding, established migration boundaries and gathered evidence that each step was safe.

We're now turning that experience into a Gleo Playbook, so that the way of working can be reused rather than remaining implicit knowledge from one Beach engineering project. In a sense, that brings the whole journey full circle. Our ambitions for Gleo were one of the reasons we needed Forge to be ready for what comes next; the experience of getting Forge there is now becoming part of Gleo itself.

Want to learn more?

We write about AI, product strategy, and the future of building. Get in touch to continue the conversation.

Start a conversation