Urgent.News

What's breaking now, across thousands of outlets.

Tech

What Broke When I Moved Client Projects to the Next.js App Router

Moving client projects from the Pages Router to the Next.js App Router sounded like a routine upgrade — until it wasn't. Every migration I've done has surfaced the same handful of breakages. Here are the four that cost me real hours, and how I fix them now. 1. getServerSideProps doesn't exist anymore The first thing that breaks is data fetching. There is no getServerSideProps in the App Router —…

Upgrading client projects from the Pages Router to the Next.js App Router appeared to be a simple enhancement — until it turned out to be more complicated than anticipated. During all the migrations I've handled, the same set of issues tended to surface. Here are four migration challenges that resulted in significant time loss, and how they were resolved.

1. getServerSideProps no longer exists. In the App Router, data fetching is handled through server components, which directly fetch data:

```

export default async function Dashboard () {

const res = await fetch('https://api.example.com/stats', {

cache: 'no-store', // opt out of default static caching

});

const stats = await res.json();

return <StatsGrid stats={stats} />;

}

```

A common mistake was to overlook the default caching behavior in server components, which led to outdated data being displayed. When porting SSR pages, it's essential to verify your desired caching behavior.

2. The 'use client' boundary moves frequently. By default, every component is now a server component in the App Router. The introduction of a client-only dependency — such as a chart library or a drag-and-drop widget — causes a build failure. The solution is to add the 'use client' directive as far down the tree as possible, allowing the rest of the page to still render on the server:

```

use client

import { LineChart } from 'some-chart-library';

export function ChartCard({ data }) {

return <LineChart data={data} />;

}

```

In one project, 'use client' was applied to an entire page, unexpectedly reversing the performance gains from the migration. Keep 'use client' at the leaf components level.

3. The router API altered significantly. useRouter from next/router has been replaced by useRouter from next/navigation, while router.query is gone. Route parameters are accessed through useParams(), search parameters with useSearchParams(), and Head is now replaced by the metadata API:

```

export const metadata = { title: 'Blog post', description: 'A migrated blog post' };

export default async function Post ({ params }) {

const { slug } = await params;

const post = await getPost(slug);

return <article>{post.title}</article>;

}

```

Note that in newer Next.js versions, params is a promise that must be awaited, which might cause hidden migration issues. Maintaining a checklist of router imports and replacing them before the initial build can prevent silent failures.

4. Auth redirects require rethinking. Helpers from the Pages Router that depended on req / res do not correspond one-to-one with the App Router. Session checks must be moved into server components, and redirecting unauthenticated users is performed like this:

```

import { redirect } from 'next/navigation';

export default async function AdminPage () {

const session = await getSession();

if (!session) redirect('/login');

return <AdminPanel user={session.user} />;

}

```

In conclusion, while the App Router migration proves beneficial — server components, streaming, and colocated data fetching genuinely simplify client projects — it should be treated as a comprehensive rewrite of your routing and data layer, not a simple find-and-replace operation. Migrate route by route, keep 'use client' boundaries small, and always verify caching behavior on every page you transfer. I create production Next.js apps and AI features for clients, and you can check out more of my work at theabubakar.dev.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

The Last Script Standing: Why Government Modernization Fails When File Replication Depends on Institutional Memory

Consider a familiar modernization scenario: a script runs at 2:13 each morning, moves files between systems built in different eras, and sends an email only when something goes badly wrong.

  • Government modernization projects rely on hidden mechanisms like file replication scripts.
  • Lack of documented rationale for changes in modernization strategy.
  • Testing should focus on establishing current behavior and ambiguous cases, not just failure points.

Plugin4Shell: When Your AI Coding Agent Auto-Updates Straight Into RCE

Zero-click RCE. Four major AI coding agents. No user interaction required. Let's talk about Plugin4Shell. The Incident In September 2026, researchers disclosed a vulnerability class dubbed…

  • Plugin4Shell vulnerability affects Claude Code, Codex, Gemini CLI, and Copilot.
  • Flaw in SHA-pinned plugin commit verification allows malicious code injection.
  • Auto-update feature executes silent, unauthorized code access to agent's resources.

More from Thursday 24 September →