Why We Build Everything on Next.js App Router
React Server Components, streaming SSR, and zero-config performance — here's why Next.js App Router is our default stack for every client project.
Abdurehman Saleemi
CEO, Texagon
Our Default Stack Decision
When a new client project kicks off, the first question is always the same: what stack? For us, the answer has been Next.js App Router for the past year, and it hasn't let us down once.
Here's why.
Projects built on App Router typically see 40–60% improvements in First Contentful Paint and 30–50% smaller JavaScript bundles compared to traditional SPA approaches.
React Server Components Changed Everything
RSCs aren't just a new API—they fundamentally change how web applications work. Components run on the server, stream HTML to the browser, and ship zero client-side JavaScript by default.
What This Means in Practice
- Zero bundle cost — server components don't add to your JS payload
- Direct data access — query databases without API routes
- Better security — sensitive logic never reaches the client
- Instant loads — HTML arrives ready to render, no hydration delay
Before and After
The old way required client-side fetching, loading states, and error boundaries for every data-dependent component:
"use client";
export function BlogList() {
const [posts, setPosts] = useState([]);
useEffect(() => {
fetch("/api/posts").then(res => res.json()).then(setPosts);
}, []);
return posts.map(post => <Card key={post.id} post={post} />);
}
The new way is just... a function:
export async function BlogList() {
const posts = await loadAllPosts();
return posts.map(post => <Card key={post.id} post={post} />);
}
No client-side fetch. No loading spinner. No JavaScript shipped. Just fast HTML.
Streaming SSR: Progressive Rendering
Next.js streams your page progressively. The shell renders instantly, and slow components fill in as their data resolves.
import { Suspense } from "react";
export default function Page() {
return (
<div>
<Header /> {/* Renders immediately */}
<Suspense fallback={<Skeleton />}>
<SlowDataComponent /> {/* Streams in when ready */}
</Suspense>
</div>
);
}
Users see meaningful content instantly, even when some data takes time to load.
Image Optimization That Just Works
The next/image component handles format conversion, lazy loading, and responsive sizing automatically:
<Image
src="/blog/hero.jpg"
alt="Hero"
width={1200}
height={630}
priority
className="rounded-2xl"
/>
The Caching Layer
App Router's caching is multi-layered and powerful:
- Full Route Cache — static pages cached at build time
- Request Memoization — duplicate fetches deduplicate automatically
- Data Cache — server-side responses cache with configurable TTL
- Router Cache — client-side navigation uses cached data
For content-heavy sites like blogs and marketing pages, this means near-instant page loads after the first visit.
Use Suspense boundaries strategically—only for components with genuinely variable load times. Don't wrap everything.
Real Numbers From Our Projects
After migrating client projects to App Router:
- FCP: 1.8s → 0.9s (50% faster)
- LCP: 2.5s → 1.2s (52% improvement)
- Bundle size: 280KB → 140KB (50% smaller)
- Lighthouse: 92 → 98
When Not to Use It
App Router isn't always the answer. Highly interactive applications with complex client state (think Figma, spreadsheets) still benefit from SPA patterns. But for content sites, dashboards, marketing pages, and most SaaS products, it's the clear winner.
Our Recommendation
If you're starting a new project or planning a migration:
- Start new routes on App Router — don't rewrite everything at once
- Default to server components — only add
"use client"when you need interactivity - Invest in your content pipeline — MDX + RSC is a powerful combination
- Measure everything — Lighthouse, Core Web Vitals, real user metrics
Need help with your Next.js project? We specialize in high-performance web applications.