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 buildcatch 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
.mdxfile, 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:
- A component library version drops expression attributes silently. One MDX renderer
(
next-mdx-remotev6 in RSC mode) discards any{expression}prop with no warning — a component receivesundefinedinstead of an error. The fix isn't a code change, it's a written rule: string attributes only, on every prop. - Building against a running dev server corrupts it.
next devandnext buildshare the.nextdirectory; 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. - A markdown convenience is deliberately banned. Some projects map
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:
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:
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
- Writing CLAUDE.md after the first bug instead of before the first prompt. By the time a mistake happens, it's already shipped once.
- Trusting a rendered preview over a production build. Dev mode and
next buildcan behave differently for exactly the kind of silent failure this article documents. - 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.
- 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
.mdxfile, not application code. - 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.
- Skipping the project's own validation scripts because the framework's are green.
npm run buildsucceeding 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?
What should a CLAUDE.md file for a Next.js project include?
How do I know if Claude Code's Next.js changes are actually correct?
Muhammad Kashif
Founder and editor of Devventa, covering AI coding assistants, Next.js and the modern AI development stack.



