6 answers
The app router with server components is definitely the way to go now, but what a lot of people overlook is thinking carefully about your data fetching strategy from the start - if you go around creating fetches everywhere without a clear pattern (caching, revalidation, client vs server), it becomes a mess that's hard to refactor later. It's worth spending time early in the project to define how your data is going to flow.
There's no single "best" way because it really depends on the size and type of your project, but most people are using the app router with server components, TypeScript, and organizing by features instead of by file type - that keeps things more scalable and less of a mess when the project grows.
Next.js 2026 is at a stable point with the app router consolidated, but the truth is a lot of people structure things poorly because they don't think about scalability from day one. When you're starting out, it's easy to fall into the trap of mixing server logic with client components, and then it becomes a mess trying to refactor later. What works well is separating folders not just by features, but especially having a clear structure for where things are being fetched and processed.
One practical thing that few people mention: create a centralized config file for environment variables and endpoints from the start. It's not glamorous, but it saves you from massive duplication later. Like, instead of scattering API URLs all over different files, having a `src/config/api.ts` that you import everywhere saves you hours. It also pays off to think early about how you'll handle data cache and revalidation - Next.js offers various options (ISR, revalidateTag, etc), but you need to choose based on what you actually need, not copy what you saw in some tutorial.
The folder structure itself can follow patterns like `(group)` for related routes, `_components` for private components of the feature, and `_lib` for local utilities. The critical point is keeping server components as the default and only making client components when you really need interactivity - that solves half your performance problems on its own.
What's the size of your project, a small MVP or something that's going to grow? What's missing from the previous conversation is talking about observability from the start - logging, performance monitoring, those things that seem annoying but make all the difference once the project starts scaling. Most people only think about it when they already have problems, and then it becomes way harder to refactor.
What actually works is separating your business logic from your UI from day one - create a `lib` or `core` folder with pure functions that don't know anything about React, then reuse them in server components, client components, API routes, everything. Most people bundle everything into the component and then get stuck. Another practical thing: if the project's going to grow, set up a validation schema (Zod, Yup, whatever you prefer) right in the middle between the request and the database - saves you tons of debugging later when you're trying to figure out why some field came through as undefined in some random part of the flow.
When I structure a project, what really works is establishing clear conventions from day one - folders by feature inside app, but with a separate services layer for reusable logic! People get stuck debating app router versus pages router, but the real problem shows up later when you've got 50 pages and nobody knows where to put a validation utility. My suggestion is to create a pattern: `app/(features)/[feature]/(routes)/page.tsx`, `lib/services/` for heavy logic, and `lib/utils/` for simple stuff. Then invest time in setting up a robust `.env` and validating variables at application boot - saves you from regretting it in production!
Your answer
Log into answer.