Next.js · Lesson 15 of 15
Full-stack Project Structure
Lay out a production App Router project and keep server code off the client.
- Advanced
- 16 min read
- 3 objectives
Before this lessonLesson 14: Images, Fonts and Performance
What you will learn
- Split app, components, lib
- Mark server-only modules
- Compose a feature folder
Your Progress
0 of 15 lessons 0%
- Lessons0 / 15
- Completed0
- Est. time left~ 4 hours
Create a free account to keep your progress on every device.
A durable App Router project keeps routing in app/, reusable UI in components/, and server-only code in lib/ or colocation folders that never get imported from the client.
A layout that scales
app/
(marketing)/ # public layout
(app)/ # signed-in layout
dashboard/
components/ # presentational, safe for client or server
features/
posts/
actions.ts # "use server"
queries.ts # db reads
ui/ # feature-specific components
lib/
db.ts
auth.ts
server-only.tsMark server-only modules
// lib/db.ts
import "server-only";
import { PrismaClient } from "@prisma/client";
export const db = new PrismaClient();If a Client Component imports this file, the build fails instead of leaking secrets.
Colocate a feature
A posts feature can own its actions, queries and UI. Pages in app/ stay thin: fetch, pass props, render.
// app/posts/page.tsx
import { getPublishedPosts } from "@/features/posts/queries";
import { PostList } from "@/features/posts/ui/post-list";
export default async function Page() {
const posts = await getPublishedPosts();
return <PostList posts={posts} />;
}