The N+1 query problem occurs when code fetches a list of items (1 query), then loops through each item to fetch related data (N queries). This is the most common performance killer in web applications and scales linearly with data size — 100 users = 101 queries.
Incorrect (N+1 — one query per user in the loop):
// ❌ 1 query to get users + N queries to get postsexport async function getUsersWithPosts() { const users = await prisma.user.findMany() const usersWithPosts = await Promise.all( users.map(async (user) => { const posts = await prisma.post.findMany({ where: { authorId: user.id }, }) return { ...user, posts } }) ) return usersWithPosts}// 100 users = 101 database queries 💀
Correct (single query with include/join):
// ✅ Single query with eager loadingexport async function getUsersWithPosts() { return prisma.user.findMany({ include: { posts: true, }, })}// 100 users = 1-2 database queries ✅
Correct (batch query with IN clause):
// ✅ Two queries instead of N+1export async function getUsersWithPosts() { const users = await prisma.user.findMany() const userIds = users.map((u) => u.id) const posts = await prisma.post.findMany({ where: { authorId: { in: userIds } }, }) // Group posts by author in memory const postsByAuthor = new Map<string, Post[]>() for (const post of posts) { const existing = postsByAuthor.get(post.authorId) ?? [] existing.push(post) postsByAuthor.set(post.authorId, existing) } return users.map((user) => ({ ...user, posts: postsByAuthor.get(user.id) ?? [], }))}// 100 users = 2 database queries ✅
In Server Components (hidden N+1):
// ❌ Each UserCard triggers its own queryasync function UserList() { const users = await prisma.user.findMany() return users.map((user) => <UserCard key={user.id} userId={user.id} />)}async function UserCard({ userId }: { userId: string }) { // This runs once per card = N queries const profile = await prisma.profile.findUnique({ where: { userId }, }) return <div>{profile?.bio}</div>}// ✅ Fix: fetch all data at the parent levelasync function UserList() { const users = await prisma.user.findMany({ include: { profile: true }, }) return users.map((user) => <UserCard key={user.id} user={user} />)}