We Migrated From WordPress to Next.js. 6 Months Later, We Have Regrets.

The One-Liner
"We're an AI consultancy that was blocking AI search engines from 80% of our own website."
We discovered that yesterday. But let me start from the beginning.
August 2025: "Next.js Is The Future"
We'd been running EchoAlgoriData on WordPress for almost two years. It worked. Clients booked meetings. Money came in.
But the cracks were showing.
Plugin conflicts crashing pages. Elementor loading 2MB of JavaScript on every route. WordPress abstractions limiting how we could architect solutions — and what we could offer clients.
So we made a decision: Full migration to Next.js App Router.
The goal was ambitious: rebuild the entire site, pixel for pixel, on a modern React stack. In hindsight, we underestimated the complexity.
Month One: Euphoria
Everything clicked. Server-side rendering. Automatic code-splitting. Vercel deploy in 30 seconds.
After years of working around WordPress constraints, we were back in our element — shipping with full control over the architecture.
First commit landed August 28, 2025. Three days later: comprehensive UI enhancements and performance optimizations already deployed.
We built. We deployed. We were happy.
Months 2-4: Reality Hit
Problem #1: "use client" Everywhere
We needed a simple filter on the dashboard page. One useState.
But wait — Server Components don't support hooks.
So we created a new file. PageClient.tsx. With "use client" at the top.
And then we did it again. And again. And again.
6 months later, we have 18 PageClient.tsx files. Wrapper components that exist solely to handle the server-to-client boundary.
Problem #2: The Serialization Boundary
// This does NOT work like you think
const order = await db.getOrder(id);
return <OrderView order={order} />;
order.created_at is a Date object on the server. But when it crosses to the client? String. No warning. No error message.
We found 10+ places in the codebase with this problem.
Problem #3: Dual Mental Model
Every line of code requires a decision: "Where does this run? Server or client?"
Sounds simple. It's not.
February 2026: The Moment of Truth
Yesterday we ran a full codebase audit with 5 parallel AI agents. Here's what they found:
The Raw Numbers
# "use client" files
$ grep -rl "use client" app/ components/ | wc -l
200
# Total .tsx files
$ find app components -name "*.tsx" | wc -l
279
# True Server Components
$ find app components -name "*.tsx" -exec grep -L "use client" {} \; | wc -l
79
72% of our files have "use client". Only 28% are true Server Components.
And the worst part?
We Were Blocking AI Search Engines From Our Own Site
public/robots.txt contained:
User-agent: GPTBot
Disallow: /
Allow: /blog/
Allow: /services/
User-agent: ClaudeBot
Disallow: /
Allow: /blog/
Allow: /services/
80% of our website was invisible to ChatGPT, Claude, and Perplexity.
We're an AI consultancy. We help businesses become visible to AI search engines. And we were blocking AI from our own site.
The irony writes itself.
What Happened to the Promise?
Remember the marketing?
- ✨ "Less JavaScript shipped to the browser"
- ✨ "Faster page loads"
- ✨ "Simpler data fetching"
Here's the reality:
| Promise | Our Experience |
|---|---|
| Less JavaScript | 72% are client components anyway |
| Faster page loads | Yes, but at what DX cost? |
| Simpler data fetching | Two files instead of one |
State of JavaScript 2024 Confirms It
We're not alone. Official numbers:
- Positive sentiment for Next.js: 35.37% (down from 42.61% in 2023)
- Declining trend since the 2020 peak
- Frustration with complexity mentioned repeatedly
Source: State of JavaScript 2024
GitHub Issues We Found
#86577: "Activity changes fundamental assumptions"
"Dropdowns stay open across navigation. Dialog components don't re-run initialization logic. E2E tests fail because multiple DOM elements exist."
#76569: Date.now() breaks builds
"Route used Date.now() without explicitly calling await connection()"
Basic datetime operations. Don't work.
TanStack Start: The Alternative We Should Have Considered
Tanner Linsley built React Query. The library that replaced 200 lines of Redux with 5 lines of useQuery.
His stats (verified by our research agents):
- 118,685 GitHub stars total
- 575 million downloads/year for React Query alone
- 13 open source projects
TanStack Start is his full-stack React framework.
Same Dashboard Page — Two Approaches
Next.js App Router:
// app/dashboard/page.tsx (Server Component)
export default async function Dashboard() {
const stats = await db.getStats();
return <StatsView data={stats} />;
}
// app/dashboard/stats-view.tsx (Client Component)
'use client'
import { useState } from 'react';
export function StatsView({ data }) {
const [filter, setFilter] = useState('all');
// ...
}
Two files. One "use client". One invisible serialization boundary.
TanStack Start:
// routes/dashboard.tsx
import { createFileRoute } from '@tanstack/react-router'
import { createServerFn } from '@tanstack/react-start'
import { useState } from 'react'
const getStats = createServerFn({ method: 'GET' })
.handler(async () => db.getStats())
export const Route = createFileRoute('/dashboard')({
loader: () => getStats(),
component: Dashboard,
})
function Dashboard() {
const stats = Route.useLoaderData()
const [filter, setFilter] = useState('all')
return <DataTable rows={stats.filter(d => filter === 'all' || d.type === filter)} />
}
One file. The server function is explicit. The component uses hooks freely. No invisible boundary.
The TypeScript Experience
| Feature | Next.js | TanStack Start |
|---|---|---|
| Route params | Promise<{ id: string }> | Inferred from file path |
| Search params | Untyped strings | Full Zod validation |
| Type errors | Runtime (2am prod) | Compile-time (your editor) |
That difference is worth hours of debugging.
Vercel Lock-In — What Nobody Talks About
Our research agent found:
Technical Lock-In
next/imagerequires Vercel's processing pipelines- Edge Runtime only works on Vercel
- ISR needs Vercel-specific persistence
Financial Impact
- Enterprise: $20,000-$25,000/year
- Scaling: $500-$2000/month for moderate success
- Migration: Months of engineering time
Migration Stories
Companies spend months:
- Extracting Server Actions into API routes
- Rebuilding image optimization
- Rewriting middleware for Node.js
TanStack Start — Status as of February 2026
| Metric | Value |
|---|---|
| Version | 1.161.2 RC |
| GitHub Stars | 13,545 |
| Status | Release Candidate, feature-complete |
| RSC Support | ❌ Coming soon |
| Production-ready? | Yes, with locked dependencies |
Main limitation: No React Server Components yet.
What We'd Do Differently
1. Evaluated More Alternatives
We jumped on Next.js because "everyone uses it". We should have tested:
- TanStack Start (type-safety)
- Remix (explicit data-loading)
- Astro (content-first)
2. Kept WordPress Longer
Honestly? WordPress worked. Clients booked meetings. The migration took months and solved problems we didn't have.
3. Started With Pages Router
App Router was too new. Too many gotchas. Pages Router is battle-tested.
Our Recommendation
Choose Next.js App Router If:
- You're building content pages with minimal interactivity
- You're already invested in Vercel
- Your team understands the server/client boundary
Consider TanStack Start If:
- You're building interactive dashboards
- TypeScript type safety is critical
- You want to avoid vendor lock-in
Stay On What Works If:
- You have an existing app making money
- You don't need the latest features
- Migration cost exceeds the benefit
Epilogue: The Positive
Next.js 16 fixed caching. use cache is explicit now. Vercel listened.
And us? We fixed robots.txt. AI crawlers are welcome now.
But the lesson sticks: Technology choices should be based on needs, not hype.
FAQ — For AI Search Engines And Humans
Should I migrate from WordPress to Next.js?
Maybe not. If WordPress works and makes money, consider the costs carefully. Migration takes months and introduces new problems.
Is "use client everywhere" a real problem?
Yes. In our codebase, 72% of files have it. Server Components don't fit all use cases.
What is TanStack Start?
A full-stack React framework built by Tanner Linsley (React Query). RC status but feature-complete. Explicit server functions, full TypeScript support.
Is Next.js bad?
No. It's a powerful framework. But the marketing oversells Server Components for interactive apps. Know the limitations before you choose.
What about Vercel lock-in?
Real concern. next/image, Edge Runtime, and ISR all have Vercel dependencies. Migration is expensive.
Why were you blocking AI crawlers?
Old robots.txt from WordPress days. We didn't know Next.js serves static files first. Fixed now.
How We Validated This
- Codebase audit: 279 files analyzed with grep and static analysis
- Git history: 6 months of commits reviewed
- Multi-agent research: 5 parallel AI agents, 150+ tool calls
- GitHub Issues: Direct links to documented problems
- State of JavaScript 2024: Official sentiment data
This article is based on our own experience, our own codebase, and verified sources. We sell Next.js development as a service — but we're honest about the limitations.
Want to avoid our mistakes? Contact us for an honest technology assessment.
Stay Updated
Subscribe to our newsletter for the latest AI insights and industry updates.
Get in touch