AI models still struggle with the Next.js App Router. We explain why they keep adding

Why AI Models Reach for 'Use Client'

Large language models learn from the code that already exists, and most of the React code written before the App Router assumed everything ran in the browser. Hooks like useState and useEffect, event handlers, and access to window were the default reality of a component. When a model predicts the next token for a React file, it leans on that history, so it sprinkles 'use client' at the top of files to make the familiar patterns compile.

The App Router inverts that default. Components are Server Components unless you opt out, and the opt-out is exactly the directive the model keeps adding out of habit. The result is code that runs, which makes the mistake hard to notice, but quietly discards the benefits the server model was supposed to provide.

What the Hallucination Actually Costs

A stray 'use client' doesn't throw an error. It changes where code runs. Everything below that boundary ships to the browser as JavaScript, re-renders on the client, and loses the ability to talk directly to your database, filesystem, or server-only secrets. A component that could have been rendered once on the server now becomes an interactive bundle the user has to download and hydrate.

Because the app still works in development, the regression tends to surface later as a heavier bundle, slower first paint, or a confusing need to build an API route for data the server component could have fetched inline. The directive is contagious too: mark a parent as a client component and its imported children are pulled across the boundary with it.

How to Guide the Model Correctly

The fix is to treat the client boundary as something you place deliberately, not something the model scatters. Server Components should be the default, and 'use client' belongs only on the smallest leaves that genuinely need interactivity or browser APIs. When you prompt an AI assistant, say so explicitly and ask it to justify any client directive it writes.

  • State the target: "This is a Next.js App Router Server Component. Do not add 'use client' unless a hook or event handler requires it."
  • Push interactivity down. Keep data fetching and layout on the server, and isolate the interactive piece into its own small client component.
  • Ask the model to explain why a directive is needed. If it can't name a hook, event handler, or browser API, remove it.
  • Pass server-fetched data into client components as props instead of re-fetching in the browser.

Reviewing AI-Generated App Router Code

Because the mistake compiles cleanly, code review has to catch it rather than the build. Scan every generated file for a top-of-file 'use client' and confirm there is a concrete reason for it. If the component only reads data and renders markup, the directive is almost certainly wrong and can come out.

It helps to think of the boundary as a checklist rather than a vibe. Does this component use state, effects, refs, event handlers, or something that only exists in the browser? If none of those apply, it stays on the server. Holding the model to that same question during generation, and again during review, keeps the App Router working the way it was designed instead of quietly collapsing back into a client-rendered app.

Automate Your Content with AI Video Generator

Try it Free →