Tips for Setting Boundaries Between Server and Client Components in Next.js 15 App Router
I'm currently refactoring a project with Next.js 15 and I'm struggling with where to draw the line between server components and client components.
For example, data fetching should happen on the server, while interactions (button clicks, form submissions) need to be handled on the client. How should I structure this within a single page for best practices?
Right now, I'm importing only the necessary parts as client components inside a large server component, but the props drilling is getting quite heavy. Would it be better to separate them at the layout level instead? I'd appreciate advice from anyone with experience.
3 answers
I had a similar dilemma. My approach is to keep data-fetching parts as server components and separate only the UI fragments that require interaction into client components. Props drilling can be significantly alleviated by using React Context or Server Actions. For example, calling a Server Action on a button click allows processing without passing props. While separating by layout units is also a good idea, I recommend breaking things into smaller units, as splitting too broadly can actually increase complexity.
Personally, I approach it as 'server components as containers, client components as presentational.' Using a pattern where the server receives data and passes it to client components as children reduces props drilling. For example, fetching data in ServerComponent, wrapping ClientComponent, and rendering it as {children}. The use hook in Next.js 15 can also help, so check it out. I only separate layouts at a very high level (e.g., sidebar vs. main content).
I was in the exact same situation, but it got much cleaner once I followed the principle of 'server components handle data fetching and initial rendering, while client components handle user actions.' If props drilling becomes too severe, you can either process related data with server actions or introduce a lightweight state management library like zustand in the client area. I also tried splitting by layout units, but it actually made management harder due to too many files. Try breaking things down into smaller units and actively using server actions!