Most studio-side technology choices are not battles between competing frameworks; they are decisions about which trade-offs you are paying for. We default to Next.js for the majority of new business applications, and this post is the technical reasoning behind that choice, including where we deliberately do not use it.
This is a technical post for engineering audiences. If you are an operator looking to evaluate a partner, the relevant question is "is your default stack defensible?", this post is the long-form answer.
What we mean by "business apps"
Throughout this post, "business apps" means:
- Multi-page web applications with significant content (marketing pages plus interactive functionality)
- Applications with a meaningful authentication / authorization layer
- Applications that integrate with multiple external services (CRM, payments, email, AI APIs)
- Applications expected to live and evolve for 3-5+ years
This is most of what an SMB-to-mid-market client builds. It is not most of what a hyperscale consumer app builds (those have different constraints), and it is not most of what a single-page tool builds (those have different constraints too).
The default-stack we ship in 2026
For a typical new business app, our default starts looking like this:
- Framework: Next.js (App Router, server components by default)
- Language: TypeScript with strict mode
- Database: Postgres (via Supabase for most engagements; managed Postgres elsewhere for clients with existing AWS / GCP commitments)
- Auth: Supabase Auth or Clerk depending on the auth model needed
- Hosting: Vercel for most projects; Netlify for clients with an existing Netlify setup; Cloudflare Pages for very high-traffic edge-distributed cases
- Styling: Tailwind CSS with a project-specific design token layer
- Email: Resend (transactional) + a marketing platform per client preference
- Background work: Inngest, Trigger.dev, or Cloudflare Queues depending on the workload
- AI: OpenAI / Anthropic / open-source models behind a thin abstraction layer
This stack is the default. We deviate when the project warrants, section at the end of the post covers when.
Why Next.js specifically
Six reasons, in roughly the order they matter for business apps:
1. Single framework for SSR, SSG, ISR, and full client interactivity
Business apps need all four:
- SSR for authenticated dashboards where data is per-user and freshness matters
- SSG for marketing pages where speed and SEO matter and content rarely changes
- ISR for content pages that change occasionally (portfolio items, blog posts, team profiles) and benefit from CDN caching with revalidation
- Client interactivity for the components users actually interact with
Next.js lets us choose the rendering and caching behavior that fits each route and component. The unified model is useful when one product combines public content, authenticated application surfaces, and interactive tools.
2. Server components solve the "what runs where" problem
Before server components, every component started as a client component, and you had to consciously work backward to push logic to the server. With server components as the default, every component starts on the server, and you opt into client-side behavior only where it is needed. This inverts the right default.
The practical impact is architectural, not a universal percentage: data access and non-interactive UI can remain on the server, while state, event handlers, and browser APIs define the client boundary. That can reduce client JavaScript when the boundary is kept narrow, but the result must be measured on the actual application.
3. The metadata API ships SEO without an extra layer
The metadata and generateMetadata exports cover common per-route metadata without adding a client-side head library. Titles, descriptions, canonical URLs, and social cards can stay close to the route. JSON-LD is still rendered as structured data in the page, where it can share the route's typed content source.
For business apps where SEO matters at all (most of them), this is a meaningful productivity win and a meaningful quality win.
4. The deployment story is mature
Vercel provides the framework's native commercial platform, while other managed hosts offer their own Next.js support. A Node server or container is also a documented deployment target. Feature parity is not automatic across hosts, so caching, image handling, streaming, server functions, and runtime constraints belong in the deployment evaluation.
The point is not that every host behaves identically. It is that the framework has more than one defensible deployment path. Keeping platform-specific services behind clear interfaces reduces migration work if pricing, compliance, or infrastructure requirements change.
5. The ecosystem is dense
Authentication libraries (NextAuth, Clerk, Supabase Auth, Auth0), data libraries (TanStack Query, SWR), form libraries (React Hook Form, react-form), CMS integrations (Sanity, Contentful, Payload, Strapi, Notion), payment integrations (Stripe, Paddle), email senders, observability tools, every category has a well-maintained Next.js integration.
This matters for business apps because authentication, payments, content, email, and observability often account for more delivery risk than the page framework itself. Mature integrations still require security and failure-path review, but they reduce the amount of undifferentiated glue code.
6. Long-term sustainability
Next.js has Vercel as a commercial backer with an aligned business interest in keeping it healthy. It has a substantial open-source contributor base. It has a clear release cadence and reasonable backward-compatibility commitments. Major releases come with codemods that handle most of the migration mechanically.
For business apps expected to live for years, active maintenance, upgrade tooling, contributor depth, and the availability of engineers are material selection criteria. No framework eliminates migration risk, but choosing a well-supported default makes that risk easier to manage.
What Next.js does not solve
To be honest about the trade-offs:
Build times can get long
Production build time can become a real friction point as routes, assets, type checking, and content generation grow. Measure it in continuous integration, inspect regressions, and avoid treating a framework-wide anecdote as your performance budget.
Server component mental model has a learning curve
The "this is a server component, that is a client component" boundary is not always obvious to engineers new to the App Router. Misplaced 'use client' directives lead to hydration errors that are confusing to debug. Onboarding time for engineers new to the App Router is a real cost.
Vercel-specific features can create soft lock-in
Vercel-specific features (Edge Functions, Image Optimization, Analytics) work best on Vercel and degrade in functionality on other hosts. We deliberately use only the features that work cross-host so client lock-in is minimized, but the temptation to reach for the convenient Vercel-specific feature is real.
Edge runtime constraints can surprise
The Edge runtime (used for middleware, edge functions, and some other features) does not support all Node.js APIs. Code that works in the Node.js runtime may not work at the edge. For most business apps this is irrelevant; for apps that lean heavily on edge features, it is a recurring source of debugging time.
Server actions have rough edges
Server actions (the form-action-style server-side mutation pattern in the App Router) are useful but have rough edges around error handling, type safety, and progressive enhancement. We use them sparingly and lean on traditional API routes for most mutations.
When we reach for something else
Six scenarios where we deliberately do not start with Next.js:
1. Single-purpose tools and dashboards
For an internal-only dashboard or a single-purpose tool with no SEO or marketing surface, we usually reach for Vite + React (or Vite + Svelte for projects where the team prefers it). The build is faster, the deploy is simpler, and we are not paying for SSR machinery we do not use.
2. Real-time-heavy applications
For applications dominated by real-time WebSocket traffic (collaborative editors, live trading dashboards, multiplayer experiences), we usually reach for a stack with first-class WebSocket support, typically Cloudflare Workers + Durable Objects, or a Phoenix LiveView stack for Elixir-friendly teams.
3. Heavy-data interactive UIs
For applications that are dominated by complex client-side state (very interactive data tools, design tools, IDE-style applications), the React Server Components model fights you. We usually reach for plain React + Vite + a robust state management story (Zustand, Jotai) and accept the loss of SSR.
4. Static content sites with no interactivity
For pure marketing sites or documentation sites with no real interactivity, we sometimes reach for Astro. The output is more cleanly static, the JavaScript footprint is smaller, and the developer experience is excellent for content-heavy sites.
5. Existing engineering teams with strong framework preferences
When we extend an existing engineering team that has invested in a different framework (Remix, SvelteKit, Nuxt, Rails, Phoenix, Django), we work in their stack. Adding a second framework to a team's mental load is usually a worse trade than picking a less-preferred-by-us stack.
6. Mobile-first native applications
For applications where the primary surface is iOS and Android native apps, we usually reach for React Native (or sometimes Expo specifically). Next.js is not the right tool for the surface and trying to share code between Next.js and React Native creates more friction than it removes.
Why "boring" is the right framing
Defaulting to Next.js is, in a real sense, a "boring" choice in 2026. It is not the newest framework. It is not the framework with the most exciting demos. It is not the framework that wins on any single technical dimension.
It is the framework that scores reasonably well on every dimension that matters for business apps, has the deepest ecosystem, is most likely to still be around (and well-maintained) in 5 years, and that the largest pool of available engineers can hire into without retraining.
For business apps that need to ship and then live for years, "boring" is the correct optimization function. We deliberately avoid the temptation to chase the newest framework, because most clients are buying durability, not novelty.
Practical guidance for engineering teams considering Next.js
If you are evaluating Next.js for your business app:
- Use the App Router. Server components are the right default for new code in 2026. The Pages Router is well-supported but represents the prior generation of the framework.
- Use TypeScript with strict mode from the start. Adding strict mode later is much harder than starting strict.
- Pick a deployment target before architecting features. Vercel-specific features lock you in lightly; planning for cross-host compatibility costs little upfront and saves real money mid-life.
- Plan for the rough edges. Server actions, edge runtime constraints, and server/client boundary debugging are recurring time sinks. Budget for them.
- Set up observability early. A production Next.js app benefits hugely from structured logging, error tracking (Sentry, Datadog, similar), and request tracing. Add these in week 1, not month 6.
For a 30-minute walkthrough of whether Next.js is right for your specific application, book a consultation, we will run the trade-off matrix on your project and give you a defensible recommendation, including "no, do not use Next.js for this" when that is the right answer.
See also: custom software services, web development services, and our earlier post Custom AI Automation vs Off-the-Shelf Tools.