· 5 min read
Why We Build Client Sites with Astro
A technical breakdown of how Astro's island architecture, content collections, and build pipeline make it the right default for most production web projects.
· 9 min read · react · next.js · web development
A practical comparison of React and Next.js — covering SSR vs SPA tradeoffs, performance, deployment complexity, and real project examples to help you choose the right tool.
Ten Peaks Tech
“Should I use Next.js?” is one of the most common questions we get from clients and developers starting new projects. The answer, like most things in software, is “it depends” — but we can make that answer a lot more specific.
We’ve shipped production applications with both plain React (via Vite) and Next.js across a range of project types. This isn’t a feature comparison you can read in the docs. It’s a practical guide based on what we’ve learned about where each tool shines and where it creates unnecessary complexity.
React is a UI library. It gives you components, state management, and a rendering engine. By default (with Vite or Create React App), it produces a Single-Page Application (SPA) — a bundle of JavaScript that runs entirely in the browser.
Next.js is a framework built on React. It adds server-side rendering (SSR), static site generation (SSG), file-based routing, API routes, and a growing list of features around React Server Components. The key addition is that Next.js can render your React components on the server and send HTML to the browser.
This distinction has cascading implications for performance, SEO, deployment, and developer experience.
If your entire application is behind a login screen, SEO doesn’t matter and the initial load penalty of an SPA is a one-time cost. Dashboards, admin panels, internal tools, and SaaS products where users are logged in for extended sessions are ideal SPA territory.
A React + Vite setup gives you:
Real-time collaboration tools, interactive data visualizations, drag-and-drop interfaces, canvas-based applications — these are inherently client-side. Server rendering adds complexity without meaningful benefit because the interesting parts of the UI require JavaScript anyway.
This matters more than people admit. Next.js has a substantial learning curve beyond React: the App Router vs Pages Router distinction, server vs client components, caching behavior, middleware, route handlers, and server actions all add concepts that take time to master.
If your team is productive with React and Vite, and your project doesn’t require SSR or SSG, introducing Next.js adds overhead without proportional benefit.
Marketing sites, blogs, e-commerce storefronts, documentation sites — anything where search engine visibility is critical. Server-rendered HTML is immediately crawlable by search engines. SPAs can be crawled (Google’s crawler executes JavaScript), but SSR is more reliable and produces better Core Web Vitals scores.
That said, if your project is purely content-focused with minimal interactivity, consider whether Next.js is even the right tool. Static site generators like Astro produce faster sites with less JavaScript for content-first projects. We use Astro for most content sites, including this one.
Next.js shines when your pages need data that’s available on the server — database queries, authenticated API calls, content from a CMS. Server Components let you fetch data directly in your component tree without exposing API endpoints or managing client-side loading states.
For example, a product page that needs to fetch inventory data, pricing, and reviews can do all of that server-side and send a fully rendered page to the browser. The user sees content immediately instead of watching loading spinners.
Next.js API routes (or Route Handlers in the App Router) let you build backend endpoints alongside your frontend code. For small to medium applications, this eliminates the need for a separate backend service.
We’ve built several internal tools and SaaS products where a Next.js monolith was the right choice — the team could deploy one application instead of coordinating frontend and backend deployments separately.
Next.js middleware runs before a request reaches your page, enabling authentication checks, redirects, A/B testing, and geolocation-based routing at the edge. If your application needs request-level logic, Next.js provides a natural place for it.
The common claim is “Next.js is faster because of SSR.” This is an oversimplification.
For the first page a user visits, server-rendered HTML appears faster because the browser can paint content before JavaScript loads. A well-optimized Next.js page will have better Largest Contentful Paint (LCP) and First Contentful Paint (FCP) than an equivalent SPA.
The margin depends on your page’s JavaScript weight. If your SPA is 150kb of JavaScript, the difference is small. If it’s 800kb (common with large component libraries and data fetching dependencies), the difference is significant.
After the initial load, an SPA has all its code cached in the browser. Navigation between pages is instant — there’s no server round-trip. Next.js mitigates this with client-side navigation and prefetching, but the SPA model is inherently faster for in-app transitions because there’s no server involved.
A common misconception is that Next.js reduces JavaScript. It doesn’t — it changes when JavaScript loads. A Next.js page still hydrates in the browser, meaning the full React component tree eventually loads as JavaScript. Server Components (RSC) change this equation by keeping some components server-only, but RSC introduces its own complexity.
In practice, we’ve seen Next.js applications ship more total JavaScript than equivalent Vite SPAs because of the hydration runtime, router code, and RSC payload format. The perceived performance is often better because of streaming and progressive loading, but the total bytes transferred are not necessarily fewer.
Deploy anywhere that serves static files. Netlify, Vercel, Cloudflare Pages, AWS S3 + CloudFront, a $5/month VPS. No runtime to manage, no server to keep alive. You can deploy a Vite React app with a drag-and-drop to Netlify in 30 seconds.
The deployment story depends on which Next.js features you use:
This isn’t a dealbreaker, but it’s a real operational consideration. We’ve had clients who chose Next.js for a project, then discovered their hosting environment didn’t support SSR, forcing a rewrite to static export that negated the reason they chose Next.js.
A client needed an admin dashboard for managing customer accounts, viewing analytics, and configuring their SaaS product. Every user was authenticated. SEO was irrelevant. The UI was heavily interactive with real-time data updates.
We built it with React, Vite, React Query for data fetching, and Tailwind for styling. Deployment was a static build to Cloudflare Pages. The development experience was fast, the deployment was trivial, and the application performed well because there was no SSR complexity to manage.
A different client needed a custom storefront connected to a headless CMS. Product pages needed to be crawlable by search engines, product data came from an API that required server-side authentication, and they wanted preview mode for content editors.
Next.js was the right choice. Server-side rendering gave us SEO. Server Components let us fetch product data without exposing API keys. The preview mode API let content editors see draft changes before publishing.
A startup needed a marketing site with a blog, team page, and contact form. No authenticated features, no dynamic data, no complex interactivity.
We built it with Astro. Zero JavaScript shipped to the browser by default, sub-second page loads, and a perfect Lighthouse score. Both React and Next.js would have been overkill.
Here’s the framework we use when helping clients choose:
Use React + Vite when:
Use Next.js when:
Use neither (consider Astro or another SSG) when:
Next.js is not “better React.” It’s React plus a server framework, and that server adds both capability and complexity. The question isn’t which is better — it’s whether the capabilities justify the complexity for your specific project.
We’ve seen teams adopt Next.js because it’s popular, then spend weeks debugging hydration mismatches, caching issues, and deployment problems they wouldn’t have had with a simpler setup. We’ve also seen teams stick with SPAs when SSR would have solved real SEO and performance problems.
The right tool depends on the job. If you’re starting a project and want help making this decision, reach out to us. We’ll look at your requirements and give you an honest recommendation — even if that recommendation is “use a tool we don’t specialize in.” You can learn more about how we approach technical decisions on our about page.
Keep reading
· 5 min read
A technical breakdown of how Astro's island architecture, content collections, and build pipeline make it the right default for most production web projects.
· 6 min read
A detailed walkthrough of how Ten Peaks Tech takes a project from initial brief to production deployment — including how we handle scope, architecture decisions, code review, and handoff.
A senior engineer replies within one business day.