All posts
engineering

Why We Build Every Client Site on Next.js App Router

After shipping dozens of projects, we've settled on Next.js App Router as our default. Here's the reasoning — including where it struggles.

24 May 20267 min readby Hetul Chaudhary

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 →


Want to work with us?

We build custom software for startups and growing businesses. Let's talk about your project.