How to Structure a Next.js Project for AI-Assisted Development with Claude Code
Claude Code generates bloated solutions when your project structure is messy. This guide shows you how to organize Next.js 15 projects so AI assistants create simpler, more maintainable code—and why folder organization matters more than you think.
The Real Problem with AI-Generated Code
You ask Claude Code to build a simple form handler. Three minutes later, you have 47 new files, a custom state management system, and abstractions layered so deep you can't trace where your data actually flows. The code works—barely—but it's 10x more complicated than what you actually needed.
This isn't Claude's fault. This is what happens when you ask an AI assistant to work with a disorganized codebase.
When your project structure is chaotic, Claude Code makes conservative assumptions. It doesn't know which utilities already exist, so it builds new ones. It can't find your conventions, so it creates its own. It sees no clear boundaries between features, so it builds elaborate abstraction layers to compensate. The result: over-engineered solutions that are brittle and hard to refactor.
Better structure changes everything. When Claude Code can see your folder organization clearly, it generates simpler, more focused code that actually fits into your project. It reuses what already exists. It follows your patterns instead of inventing new ones.
Why Your Current Structure Isn't Working
Most developers organize Next.js projects one of two ways, and both fail when you're using AI assistants.
The first approach: throw everything in the app/ directory. Your routes, your components, your utilities, your database queries—all mixed together in nested folders that quickly become impossible to navigate. Claude Code sees this and doesn't know what's a route, what's a feature, and what's shared infrastructure. It defaults to building things in isolation.
The second approach: organize by type. All components in components/, all utilities in utils/, all hooks in hooks/. This worked for smaller projects, but it doesn't scale, especially with AI assistance. When Claude needs to build a feature, it has to reach across five different folders to connect the pieces. It can't see the domain logic clearly, so it builds things that exist elsewhere.
Both structures create the same problem: Claude Code can't understand the intent of your codebase. It only sees files and folders. When the intent is unclear, AI errs on the side of caution—which means more code, more abstraction, more complexity.
The Feature-Driven Structure That Works with AI
Instead, organize your Next.js project around features and domains, not file types.
Here's what this looks like:
```
app/
(auth)/
login/
page.tsx
layout.tsx
signup/
page.tsx
(dashboard)/
page.tsx
layout.tsx
settings/
page.tsx
src/
features/
auth/
components/
LoginForm.tsx
SignupForm.tsx
hooks/
useAuth.ts
utils/
validateEmail.ts
types.ts
api.ts
dashboard/
components/
DashboardCard.tsx
UserStats.tsx
hooks/
useDashboardData.ts
utils/
calculateMetrics.ts
types.ts
lib/
supabase.ts
middleware.ts
types/
index.ts
```
The key difference: related code lives together. Everything the auth feature needs—components, hooks, utilities, types—is in one folder. Everything for the dashboard is colocated.
This structure tells Claude Code exactly what it needs to know:
When you ask Claude Code to add a password reset flow, it immediately knows where to work: features/auth/. It can see what components already exist, what hooks are available, what database queries are defined. It doesn't duplicate logic because the existing code is right there, visible and organized.
Keeping the App Router Clean
In Next.js 15, your app/ folder should contain one thing: routing and layouts. Nothing else.
This sounds simple, but developers constantly violate it. They add form components directly in route folders. They write database queries in page.tsx files. They inline utilities that should be shared.
Stop doing that. Your page.tsx file should be about 10-15 lines. It imports a component from features/, calls it, and renders it. That's it.
```
// Good: app/auth/login/page.tsx
import { LoginForm } from '@/features/auth/components/LoginForm'
export default function LoginPage() {
return <LoginForm />
}
// Bad: app/auth/login/page.tsx
'use client'
import { useState } from 'react'
import { supabase } from '@/lib/supabase'
export default function LoginPage() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [loading, setLoading] = useState(false)
const handleLogin = async () => {
setLoading(true)
try {
const { data, error } = await supabase.auth.signInWithPassword({
email,
password,
})
// ... 30 more lines of code
}
}
return (
// ... form markup
)
}
```
When your page files are thin, Claude Code can focus on the actual feature logic. It won't get distracted by layout concerns. It won't add routing logic that belongs in middleware. It'll write the code you actually asked for.
A Critical Note on Supabase and Structure
If you're using Supabase with Next.js 15, your project structure matters even more because of a common security mistake that structure can prevent.
Most developers create Supabase tables without enabling Row Level Security (RLS). It works fine in development because they're testing with their own data. Then it ships to production, and suddenly every user can see everyone else's data.
Structure helps here too. Create a clear auth/ feature folder where all authentication logic lives. Make RLS policies part of your feature setup, not an afterthought. When database queries are colocated with their RLS policies, you're less likely to forget one.
Also: Supabase's Next.js helpers still aren't compatible with Next.js 15. Use the JavaScript client directly and wrap it in your own utility layer (in lib/). Structure forces you to do this anyway, which is actually better for your codebase.
How This Changes Your AI Workflow
When Claude Code understands your structure, it changes how you work together:
You can ask for less. Instead of "add password reset functionality with components, hooks, utilities, and database queries," you can say "add password reset to the auth feature." Claude will naturally look in features/auth/, see what exists, and build what's missing without duplicating anything.
Your refactoring becomes easier. If Claude generates code that's too complex, you have a clear place to simplify it. Extract the complexity into a utility in the same feature folder. Claude will find it next time.
You spot mistakes faster. If Claude generates code in the wrong place, you immediately know it's wrong because it violates your structure. Bad code also breaks the organization, making it obvious something's off.
Your codebase stays maintainable even as it grows. Every feature is self-contained. You can move features around, delete them, or refactor them without touching everything else.
Getting Started
Start with a new Next.js project and implement this structure from day one. Put your first feature in features/ instead of directly in app/. It feels like extra overhead for small projects—it isn't. It's the foundation that scales.
If you're retrofitting an existing project, pick your largest feature and reorganize it first. See how it changes your workflow with Claude Code. Then move the next feature. Don't try to reorganize everything at once.
The investment pays off immediately. Your AI-assisted development becomes faster, your code becomes simpler, and your project stays clean even as it grows.
If you're building a production SaaS app and need help structuring this from the start—including proper Supabase setup with RLS, authentication flows, and scalable architecture—try the free discovery chat at zipbuild.dev. We've helped dozens of teams ship clean, AI-friendly codebases without the over-engineering mess.
Written by ZipBuild Team
Ready to build with structure?
Try the free discovery chat and see how ZipBuild architects your idea.
Start Building