Skip to content

NEXT.JS

Using Claude Code with Next.js: A Practical Workflow

A claude code nextjs workflow that actually holds up: what belongs in CLAUDE.md, which failures Claude Code cannot infer on its own, and how to verify its work before you trust it.

Using Claude Code with Next.js works well once you stop treating CLAUDE.md as documentation and start treating it as the list of failures a generic model can't see coming. Claude Code reads your package.json, tsconfig.json, and next.config file on startup and already understands App Router conventions — the gap isn't framework knowledge, it's your project's specific silent failure modes. This walkthrough is built from a real Next.js 15 + MDX project, including a real build error hit and fixed while writing it.

Key takeaways

  • Claude Code indexes package.json, tsconfig.json, and your Next.js config on startup, so framework-level conventions rarely need explaining — project-specific silent failures do.
  • The highest-value CLAUDE.md content is the failure that doesn't throw an error: a dropped JSX attribute, a build that corrupts a running dev server, a markdown pattern mapped to a build-time error.
  • A type check and a full next build catch problems a visual diff review does not, because MDX and templating pipelines can fail silently rather than with a stack trace.
  • Every claim in this article about what breaks is from a real build run against a real .mdx file, not a hypothetical.

Prerequisites

You need three things before Claude Code adds any real value on a Next.js project: the Claude Code CLI installed and authenticated, a Next.js 15+ App Router project already initialized with git, and — this is the part most setups skip — a CLAUDE.md file written before the first real prompt rather than after the first mistake. None of these are exotic requirements; the workflow below assumes only that you can run npm run build locally.

Step 1: write CLAUDE.md before the first prompt

A CLAUDE.md written after Claude Code has already made a stack-specific mistake is a postmortem, not a spec. Anthropic's own memory documentation recommends structuring it with headers and keeping instructions concrete enough to check — see how to set up CLAUDE.md for the exact structure. For a Next.js project specifically, the highest-value early entries are build commands, the distinction between Server and Client Components your project actually enforces, and any non-obvious data-access pattern (an ORM choke point, an API wrapper) that a generic model would otherwise reach for the wrong way on the first try.

Step 2: let Claude Code scaffold inside the App Router

Claude Code already understands App Router file conventions — page.tsx, layout.tsx, route groups in parentheses, and the difference between a Pages Router API route and an App Router route handler — without being told. Point it at a real task ("add a /pricing route that reads plans from lib/plans.ts") rather than a vague one, and it will follow the routing convention your other files already use. This step rarely fails on its own; the failures below happen after the scaffold, once the change touches something CLAUDE.md didn't cover.

Claude Code also builds what its documentation calls auto memory as it works — saving things like the exact build command or a debugging insight across sessions without you writing them down. That's useful, but it's a supplement to a written CLAUDE.md, not a replacement: auto memory captures what Claude Code personally ran into, while a written rule captures what you already know will trip it up before it happens once. On a Next.js project specifically, that means the framework-level conventions can stay implicit, but your project's build quirks — a database binding that only exists in one runtime, a script that has to run before another — are worth writing down even if Claude Code hasn't hit them yet.

Step 3: document the traps Claude Code cannot infer

Some failures are invisible from the code alone, because the code that would explain them lives in a library's internals, not your repo. Three real examples from one production project:

  1. A component library version drops expression attributes silently. One MDX renderer (next-mdx-remote v6 in RSC mode) discards any {expression} prop with no warning — a component receives undefined instead of an error. The fix isn't a code change, it's a written rule: string attributes only, on every prop.
  2. Building against a running dev server corrupts it. next dev and next build share the .next directory; running a build while dev is live rewrites its chunk manifest and every route starts returning 500, which looks exactly like an application bug. The rule that prevents it — confirm no dev server is running before a build — has to live in CLAUDE.md, because nothing in the error message points back to the real cause.
  3. A markdown convenience is deliberately banned. Some projects map ![alt](src) to a build-time error on purpose, to force image handling through a specific component. Nothing about that convention exists in the framework — it only exists in the project's own build config, so it only exists for Claude Code if someone wrote it down.

Step 4: verify with commands, not by reading the diff

A diff that looks correct and a change that works are not the same claim, especially for MDX or templating pipelines where a broken attribute produces no error at all. Run the same checks a human reviewer would run:

Terminal
npm run typecheck
npm run build

For a project with a custom validation script — an anchor checker, a schema linter — run that too. Trusting a visual read of the diff for anything MDX-adjacent is exactly how the {expression}-attribute trap above ships to production undetected.

A real failure and what fixed it

This is the artifact, not a hypothetical: while drafting an MDX file in a real Next.js 15 project, a <!-- TODO(link): ... --> HTML comment was placed directly in the article body. The build failed with:

Terminal output
Error occurred prerendering page "/comparisons/claude-code-vs-cursor".
[Error: [next-mdx-remote] error compiling MDX:
Unexpected character `!` (U+0021) before name, expected a character that can start a name,
such as a letter, `$`, or `_` (note: to create a comment in MDX, use `{/* text */}`)

MDX does not parse HTML comments — the fix was wrapping the same text in an MDX comment instead: {/* <!-- TODO(link): ... --> */}. The error message itself named the fix, but only because the build was actually run; a diff review would have shown a harmless-looking HTML comment and missed it entirely.

What success looks like

A Next.js change made with Claude Code is done when three things are true: npm run typecheck exits clean, npm run build completes and the specific route you changed appears in the route list it prints, and any project-specific validator (anchors, schema, lint) passes. "It looks right in the preview" is not on that list — the build step above is the one that catches what a preview can't.

It's worth being specific about why the route list matters and not just the exit code. A build can succeed overall while a single dynamic route silently fails to prerender if a data source it depends on is unreachable at build time — the process still exits 0 for everything else. Reading the printed route table and confirming the page you actually changed is in it closes that gap in a way that "the command didn't error" does not.

Common mistakes

  1. Writing CLAUDE.md after the first bug instead of before the first prompt. By the time a mistake happens, it's already shipped once.
  2. Trusting a rendered preview over a production build. Dev mode and next build can behave differently for exactly the kind of silent failure this article documents.
  3. Assuming a generic AI-coding guide covers your stack's specific traps. Framework conventions are shared; a project's build config, banned patterns, and internal APIs are not.
  4. Not re-running the build after touching MDX or templating content, on the assumption that "it's just content" — the real failure above was in an .mdx file, not application code.
  5. Relying on auto memory instead of a written rule. Auto memory records what Claude Code has already hit; it does nothing for a trap the current session hasn't encountered yet, which is exactly the category of failure a CLAUDE.md rule is supposed to prevent in advance.
  6. Skipping the project's own validation scripts because the framework's are green. npm run build succeeding says nothing about a project-specific check — a heading-anchor validator, a schema linter — that catches a different class of mistake entirely.

Conclusion

Claude Code already knows Next.js; what it doesn't know is your project's specific failure modes until you write them down. Start with a CLAUDE.md before the first prompt, add a rule every time something fails silently instead of erroring, and verify with a real build rather than a diff read. Once the app builds cleanly, deploying it to Vercel is the natural next step — see more Next.js guides for the deployment and configuration details this piece doesn't cover.

Frequently asked questions

Does Claude Code work well with Next.js App Router projects?
Yes — Claude Code reads your package.json, tsconfig.json, and next.config file on startup, and understands the difference between Pages Router API routes and App Router route handlers. It does not automatically know your project's silent failure modes, though, which is why a project-specific CLAUDE.md matters more than the framework choice itself.
What should a CLAUDE.md file for a Next.js project include?
The rules a generic model would get wrong for your specific stack: which MDX or templating traps silently fail instead of erroring, build-versus-dev-server conflicts, database or API access patterns unique to your deployment target, and any convention (like never hand-writing a slug or an anchor) that isn't visible from the code alone. Keep it under roughly 200 lines per Anthropic's own memory guidance.
How do I know if Claude Code's Next.js changes are actually correct?
Run the same commands you'd run in code review: a type check, your project's lint or anchor-verification script, and a full production build. A change that compiles in dev but fails typecheck or build has not been verified — reading the diff is not equivalent to running it, especially for MDX or templating pipelines where a broken attribute fails silently rather than with an error.

Muhammad Kashif

Founder and editor of Devventa, covering AI coding assistants, Next.js and the modern AI development stack.