Next.js
The default way to build production React applications. Server and client rendering in a single component model with built-in performance optimisation.
Production React, batteries included
Next.js is how we build React applications that face the public web. It supplies what the library leaves open, server rendering for first paint and search, file-system routing, image and font optimisation, code splitting, as framework conventions that every React project once assembled from scratch.
The App Router is the centre of the current framework. Layouts, loading states and error boundaries are files; Server Components fetch data where it lives; Server Actions let a form mutate data without a hand-written API endpoint. Rendering is decided per route, static at build time, revalidated on an interval, or fully dynamic, and the decision can change as the product does.
Adopting Next.js is adopting a server. Rendering happens per request unless a route is static, and the caching layer becomes part of the application's behaviour rather than a bolt-on optimisation. That operational surface is the framework's real learning curve, and we treat it as architecture rather than as a deployment detail.
Where every user signs in before seeing a page, an internal dashboard, an admin tool, an editor, Next.js is usually the wrong choice: there is no search ranking to win and no anonymous first paint to optimise, and a client-rendered React application is simpler to build and operate. Next.js earns its place where the public web is the audience.
Next.js was used by 20.8% of respondents to the 2025 Stack Overflow Developer Survey.
Next.js has shipped a major release roughly once a year since 2020.
- SaaS Products
- Marketing Sites
- Dashboards
- Headless CMS
Our Next.js capabilities
App Router & Server Components
The App Router rewards being taken on its own terms, so applications are structured around its conventions: layouts own the chrome and persist across navigations, pages own data, and loading and error states are declared beside the routes they serve. The server/client boundary is drawn explicitly, with client components kept to the interactive leaves. Streaming through Suspense means a slow data source delays its own section of the page rather than the whole response.
- App Router
- Server Components
- Streaming
Server Actions & mutations
Server Actions remove the hand-written API layer for first-party mutations: a form posts to a typed server function, and revalidatePath or revalidateTag refreshes exactly the cached data the mutation touched. Actions are treated as the trust boundary they are, with input validated by Zod and authorisation checked inside the action rather than trusted from the client. Progressive enhancement comes with the model, since the form submits before JavaScript has loaded.
- Server Actions
- revalidatePath
- Form handling
Static & dynamic rendering
Rendering strategy is a per-route decision, and most applications end up blended: marketing pages static, catalogue pages revalidated on an interval, account pages dynamic. Caching behaviour is declared explicitly rather than inherited, because implicitly cached routes are where production surprises concentrate. The edge runtime carries middleware and personalisation, where proximity to the user pays; heavier routes stay on the Node.js runtime.
- ISR
- Static generation
- Edge runtime
Why Adaca for Next.js?
App Router experience
Production App Router applications navigating caching, parallel routes, and server/client boundaries.
Core Web Vitals focus
LCP, INP, and CLS measured in production with real user monitoring, not just Lighthouse scores.
Self-hosted & Vercel
Deployment on Vercel, AWS via SST, and Docker with ISR, image optimisation, and edge middleware.
Headless CMS architecture
Integration with Contentful, Sanity, Payload CMS with preview mode and webhook revalidation.
Authentication patterns
NextAuth.js or Clerk with middleware route protection and role-based access in server components.
Incremental migration
CRA, Gatsby, and Pages Router to App Router incrementally, running old and new routing side by side.
How We Staff It
Next.js staffing is React staffing with the server half added: engineers who work both sides of the server/client boundary and treat caching and deployment as part of the application. Most briefs ask for full-stack engineers who own a feature from data access to rendered page.
The pool behind it is the same TypeScript pool that covers our React and Node.js work, so an engagement can widen to the API layer or narrow to the front end without a new search. Hours follow your working day.
Common Questions
Do we need Next.js, or is a plain React SPA enough?
The dividing line is the anonymous visitor. Where search ranking, link previews and first paint on slow connections carry commercial weight, server rendering pays for itself and Next.js is the standard way to have it in React. Where they do not, a single-page application built with Vite keeps the operational surface small: static files on a CDN, no render fleet, no framework caching model to own.
Both are React, so a product that starts as a single-page application can adopt Next.js later if its audience changes; the migration is real work but a bounded one. Starting with Next.js for an internal tool buys the cost without the benefit.
We are on the Pages Router. Should we move to the App Router?
Migrate route by route, and only when a route needs what the App Router provides: streaming, nested layouts, Server Components. The two routers coexist in one application, so there is no cutover moment.
The real cost is conceptual rather than mechanical. Data fetching and caching work differently across the two models, and a team mid-migration holds both in its head at once. We convert the shared shell first, then move routes as feature work touches them, keeping the mixed period short in the parts of the application that change most.
Can AI coding tools keep up with how fast Next.js changes?
This is the stack where corpus lag is most visible. Next.js has changed its core idioms twice in recent memory, and the public code that agents learn from still holds far more Pages Router material than current practice. Left to its defaults, an agent will write getServerSideProps into an App Router application, or apply the caching semantics of a version you do not run.
The remedy is specificity: the framework version pinned and stated where the tooling reads it, current documentation supplied as context, and lint rules plus review catching idiom drift at the boundary. Under that discipline agents are productive in Next.js; without it they quietly write for a framework two majors old.
Does it matter which Next.js version we standardise on?
More than in most frameworks, because behaviour as well as API changes across majors: caching defaults in particular have shifted, and code that was correct under one major can be subtly wrong under the next. Pinning a version means a lockfile, caching behaviour declared explicitly rather than inherited, and upgrades run as scheduled engineering work with the release notes read.
The pinned version also defines correctness for AI-assisted work: it is the answer to which idioms are right for this repository, so it belongs where both engineers and agents will read it, and output written for another version is treated as a defect.
Do we hire Next.js specialists or full-stack engineers?
In practice they are the same people. An engineer effective in Next.js works both sides of the server/client boundary, data access, caching and deployment included, so we staff full-stack TypeScript engineers with Next.js depth rather than a separate specialism. A build usually starts with one or two, adding design-system or infrastructure depth as the product firms up.
Terms are chosen up front from three, six, nine or twelve months.
How quickly can Next.js work start?
A shortlist of engineers usually reaches you within 48 hours of a brief, drawn from people we already employ or already know. Work starts at one engineer, and engineers keep your working day.
For a defined first outcome, a site launch, a router migration, an initial build, the engagement can be priced as a fixed cost for that outcome instead of a monthly team rate; the People pages set out both models.