Published: April 21, 2026
You paid a developer. They delivered a site. It looks finished. But your team can't edit it, it doesn't show up on Google, and nobody can explain why. You're not sure if the problem is fixable or if you need to start over.
This is a pattern I keep seeing. It has a name now: vibe coding. And the damage it leaves behind is almost always the same.
Here's what I found when I took over one of these projects.
The client reached out after firing two developers. The second one had delivered a finished-looking website on time. Clean layout, smooth animations, the right pages in the right places. The client had signed off because it looked right.
They were a global policy and advocacy organization. Their site needed to communicate their work across regions, keep team bios up to date, publish articles and event updates, and generally reflect an active, credible institution. None of that was working in practice.
What they had was a website nobody on their team could edit. A Sanity CMS subscription they had been paying for while getting nothing out of it. And a contact form that silently dropped every message.
When I opened the codebase for the first time, I understood immediately why two developers had already failed.
The Sanity subscription had been running for months. Not a single piece of content had ever been connected to the frontend.
Every page was hardcoded. The homepage hero text, the services section, the team member names and bios, the regional engagement articles, all of it was written directly into JSX components. Strings in code. No schema, no GROQ queries, no connection to the CMS the client was paying for every month.
To change the organization's tagline, you needed a developer, a code editor, and a deployment pipeline. To update a team member's photo after a leadership change, same thing. The client had been sold a content-managed website and received a static brochure that looked dynamic.
The SEO situation was just as bad. The site was running entirely client-side, no server-side rendering, no static generation. When Googlebot crawled the pages, it saw blank HTML shells. The JavaScript that populated the content never executed. The site had been live for months with effectively no indexable content at all.
On top of that: no <meta> descriptions, no Open Graph tags, no canonical URLs, no sitemap, no robots.txt. Every page had the same generic <title> tag from the Next.js starter template.
The UI carried its own problems. The header hierarchy was broken throughout — h3 elements appearing without a preceding h2, jumping levels in a way that broke screen reader navigation. The lang attribute was missing on several pages. Empty subtitle sections rendered as invisible gaps in the layout instead of simply not appearing. The mobile menu extended outside the viewport on smaller devices and wasn't scrollable. The button to open and close it was in different positions depending on which page you were on.
The contact form accepted input and showed a success state. It never actually sent anything.
I want to be clear about something: this isn't a story about a developer who didn't try. It's a story about a developer who didn't know what they didn't know, and used AI tools to fill that gap in a way that hid the gap rather than closing it.
Vibe coding, using AI code generation tools to build fast without deeply understanding what's being generated, produces code that looks correct because AI models are trained on syntactically correct code. The output passes a visual inspection. It might even pass a basic functionality check. What it doesn't do is make the architectural decisions that production software requires.
Integrating a headless CMS isn't just writing GROQ queries. It's modelling content schemas, thinking through editorial workflows, deciding what belongs in the CMS versus what's configuration, handling draft and published states. None of that is a code generation problem. It's a product thinking problem that requires experience to solve.
Setting up SSR or static generation in Next.js isn't just switching a rendering mode. It's understanding when each approach is appropriate, how it affects caching, what it means for dynamic data, how to handle revalidation. You can't prompt your way to those decisions. You have to have made them before and seen the consequences.
The client's mistake wasn't hiring someone who used AI. AI tools make developers faster and I use them myself. The mistake was hiring someone who used AI as a substitute for experience rather than an accelerator of it. The output was plausible-looking code with no architecture underneath it.
This pattern is becoming more common, not less. The barrier to looking like a developer keeps dropping. The barrier to being one hasn't moved.
The first thing I did was model the content schemas in Sanity properly. The site had six distinct content types that needed CMS management: service and programme pages, team member profiles, regional engagement articles, events, general blog posts, and site-wide settings covering navigation, footer, and contact details. I built out the schemas, configured the editorial interface so the client's team could use it without training, and replaced every hardcoded string in the codebase with GROQ queries.
The client went from zero CMS control to being able to manage their entire site content, without touching code, within the first week.
The SSR migration came next. I moved the key landing pages and programme pages to Next.js server components with full server-side rendering. The article and event pages got static generation with incremental revalidation, so they rebuild automatically when content is published or updated in Sanity. Googlebot could now actually read the pages.
The SEO layer went in alongside the rendering work. Dynamic <title> and <meta> tags driven by Sanity content fields. Open Graph data generated per page. A sitemap built from CMS content. Canonical URLs on every page. robots.txt in place. Menu items now show or hide in navigation and footer based on whether a page is published, which meant no more dead links pointing to empty routes.
The WCAG and accessibility fixes ran in parallel. I corrected the heading hierarchy across all templates, added the missing lang attribute, fixed the empty subtitle rendering, and built proper not-found pages for dynamic routes so 404s behaved correctly instead of falling through silently.
The mobile menu got rebuilt: scrollable, consistent button placement, works across device sizes.
The contact form was rewired to actually deliver messages.
The whole engagement ran to around 50 hours of work across roughly three months, with the core rescue completed in the first few weeks and the remaining time spent on documentation, content migration support for the client team, and polish.
The client had paid two developers. They had a Sanity subscription running unused. They had a live website that ranked for nothing, that their team couldn't edit, and that dropped every contact form submission.
The rescue engagement cost less than what they had already paid the second developer alone.
What they got at the end: a site the communications team manages independently from day one, pages that Google can index, a contact form that works, accessibility compliance, and a content model that matches how the organization actually operates.
The real cost of bad development isn't the invoice. It's the months of delay. The tool subscriptions running on features nobody is using. The opportunity cost of a website that doesn't generate interest because it doesn't rank. And then paying again, a second time, sometimes a third, to get something done properly that should have been done right the first time.
If you've worked with developers in the past year, especially developers who move very fast, deliver quickly, and use AI tools heavily, it's worth a look under the hood before assuming the site is production-ready.
The warning signs I consistently see in these takeovers are: content hardcoded in JSX instead of coming from a CMS, client-side rendering on pages that should rank in search, CMS or tooling subscriptions that are active but disconnected from the frontend, and UI inconsistency that becomes obvious once you look at more than the homepage.
None of this means the project is a write-off. Most of the codebases I've taken over didn't need to be rewritten. They needed to be finished. The UI exists. The structure is there. What's missing is the integration work, the architectural decisions, the parts that require someone who's done it before to do it right.
If you recognise any of this: a site that was handed over and "finished" but that you can't really manage, that doesn't rank, that a previous developer left in a state you can't explain, I take on Next.js rescue projects.
The first step is a 30-minute assessment. I'll look at the codebase, identify the gaps, and give you a clear picture of what's broken and what a fix actually involves. No vague estimates, no sales pitch. Just a clear read of where the project stands.
