When a new project lands on our desk, we don't spend long debating the frontend framework. We reach for Next.js with the App Router. Every time.
That doesn't mean it's perfect. It has real rough edges. But the trade-offs are consistently worth it for the type of work we do — and this article explains why.
What the App Router gets right
Server Components by default
The biggest shift in the App Router is that components are server-rendered by default. This means:
- Less JavaScript shipped to the browser
- Data fetching happens on the server, close to the database
- No loading states for the initial render — the page arrives with content
For most pages on a business website — marketing pages, blog posts, case studies — there is zero reason to ship a JavaScript-heavy client bundle. The App Router makes the right default choice automatically.
Co-located data fetching
In the Pages Router, data fetching was centralised in getServerSideProps or getStaticProps. With the App Router, you fetch data inside the component that needs it. This sounds like a small ergonomic win, but it fundamentally changes how you structure applications.
// Each component fetches its own data
async function TeamSection() {
const team = await getTeamMembers()
return <div>{team.map(m => <MemberCard key={m.id} member={m} />)}</div>
}
No prop drilling. No over-fetching at the page level. Components stay self-contained.
Streaming and Suspense
Long-running data fetches no longer block the whole page. Wrap a slow component in <Suspense> and the rest of the page renders immediately while the slow part streams in. This is a real performance win with almost no extra effort.
Nested layouts
The App Router's layout system is elegant. A shared header and footer? A layout.tsx at the root. A sidebar that only appears in the dashboard? A nested layout.tsx in the dashboard folder. No workarounds, no custom abstractions — the file system is the routing system.
Where it struggles
Honesty matters, so here are the genuine pain points:
The learning curve is steep. Understanding when a component should be a Server Component versus a Client Component trips up every developer the first time. The mental model takes a few projects to fully internalise.
Error messages can be cryptic. When something goes wrong at the boundary between server and client, the error messages are often confusing. This is improving with each Next.js release, but it's not there yet.
Caching is complex. The App Router's caching behaviour is powerful but requires careful thought. fetch calls are cached by default. Mutations need explicit cache invalidation. Getting this wrong produces stale data bugs that are hard to reproduce.
Third-party libraries lag. Some libraries assume they're running in a browser. Client-side-only libraries need to be wrapped in 'use client' boundaries. Most popular libraries have caught up, but you still hit edge cases.
Our setup
For every project, we start with the same base configuration:
- TypeScript — strict mode, no exceptions
- Tailwind CSS v4 — configured via
globals.css, no config file needed - Resend — for transactional email
- Supabase — when the project needs a database
- Vercel — hosting, auto-deploy from the main branch
We keep next.config.ts as minimal as possible. Every line in that file is a complexity cost. We add to it only when we have a specific, justified reason.
When we would choose something else
Next.js App Router is our default — not our religion.
If a client needs a purely static site with no dynamic routes and the developer team is more comfortable with another tool, we'd consider Astro. It's excellent for content-heavy sites and ships almost no JavaScript.
If the project is a highly interactive single-page application — a complex dashboard, a design tool, a real-time collaborative editor — we'd consider skipping SSR entirely and reaching for a simpler React setup with Vite.
But for 90% of what we build — marketing sites, SaaS products, portfolio sites, API-driven web apps — Next.js App Router is the right tool. The ecosystem is mature, the performance is strong, and Vercel's deployment pipeline is the smoothest we've used.
We're always happy to talk through the technical choices for your project. If you're starting something new and want an independent technical opinion, book a free call →