FISTA Solutions does not load Google Analytics until you accept. Rejecting keeps optional analytics off. Read the Cookie Policy.

All field notes

Web & Mobile · 5 minute read

Next.js App Router: What Changes and What to Watch

The App Router moves rendering to the server by default, changes where data fetching happens, and introduces caching layers that behave differently from the Pages Router. Most migration surprises come from caching and from client boundaries rather than from syntax.

By FISTA Solutions· AI-Native Engineering Team·
Next.js App Router: What Changes and What to Watch article cover

The App Router changes where code runs, where data is fetched, and how caching behaves. Most of the difficulty in adopting it comes from the last two rather than from the syntax. This guide covers what to expect, drawing on FISTA Solutions' web and mobile work.

What changes compared with the Pages Router?

Several things at once, which is why the transition feels larger than a routing change.

AreaWhat changes
RenderingServer by default, client opt-in
Data fetchingIn components, not page-level functions
LayoutsPersist across navigation, nest
CachingSeveral layers applied automatically
StreamingAvailable through suspense boundaries
BundlingDetermined by client boundary placement

How do server and client components divide?

Components are server-rendered unless marked otherwise. A client component and everything it imports ships to the browser.

That makes boundary placement the main architectural decision. A client boundary near the root pulls most of the tree into the bundle; pushing it down to the genuinely interactive leaves keeps the bundle small.

The practical pattern is server components for data and structure, with small client components for interaction, passing data down as props rather than lifting state up.

Why does caching cause so much trouble?

Several layers operate at once: request memoisation within a render, a data cache across requests, a route cache for rendered output, and a client-side router cache.

Each has its own invalidation, and the defaults have changed across versions. Stale data almost always traces to one of them, and diagnosing it requires knowing which layer is responsible.

Be explicit rather than relying on defaults. Stating the caching behaviour you want per fetch, and revalidating deliberately, is considerably easier to reason about than discovering the default in production. See caching strategy guide.

How should data fetching be structured?

Fetch where the data is used rather than at the top and passing down, and let request memoisation handle duplicates within a render.

That is a genuine simplification over prop drilling, and it changes how components are composed. Parallel fetching matters: sequential awaits in nested components produce waterfalls that are easy to create and hard to spot.

Use the tooling to check for waterfalls before launch. They are the most common performance problem in App Router applications.

What does streaming actually buy?

Perceived performance. Rendering the shell immediately and streaming slower sections means users see content while the rest loads.

That matters more than total load time for how fast an application feels. Placing suspense boundaries around the slow parts is a small change with a visible effect.

It also interacts with accessibility: streamed content needs handling so assistive technology announces it sensibly rather than flooding or staying silent. See accessibility compliance guide.

How should migration be sequenced?

Route by route, with both routers running side by side.

Wholesale migration turns every incompatibility into a blocking problem simultaneously. Incremental migration surfaces them one at a time, with the rest of the application still working.

Start with a simple route to establish the patterns, then a data-heavy one to find the caching behaviour, then the rest. Leave the most complex route until the team has built the instincts.

What about third-party libraries?

Many assume a browser environment and need a client boundary, which pulls them into the bundle.

Check each dependency early. A library that must run on the client, imported near the root, can undo the bundle benefits of the whole architecture.

Where a library is server-incompatible and central, that is a migration constraint worth knowing before committing to a timeline.

What are the common mistakes?

Client boundaries too high in the tree. Relying on caching defaults. Sequential data fetching producing waterfalls. Migrating everything at once. And measuring build output rather than field performance.

How do you test it?

Test rendering on the server and the client paths separately, check for fetch waterfalls with the tooling, and verify caching behaviour explicitly rather than assuming it.

Field performance measurement matters more than synthetic testing here, because caching behaviour differs between development and production in ways local testing does not surface.

What does it cost to operate?

Mostly hosting and compute, which rises with server rendering compared with fully static output. Streaming and server components trade browser work for server work.

For most applications the trade is favourable, and it is worth measuring rather than assuming. Applications with very high traffic and largely static content may find aggressive caching or static generation cheaper.

What should you measure?

Field Core Web Vitals rather than lab scores, bundle size shipped to the client, server response time, and cache hit rates per layer. See core web vitals guide.

How does this interact with AI features?

Streaming is the natural fit. AI responses arrive incrementally, and the App Router's streaming primitives handle that well without custom plumbing.

The considerations are keeping the model call on the server so credentials stay there, handling partial responses in the interface, and making streamed output accessible. See streaming UI patterns for AI apps.

When is this the wrong approach?

When the application is largely static content with no interactivity, where a simpler static site generator is cheaper to build and operate. And when the team has a working Pages Router application with no specific problem the migration solves.

What should you do first?

Check where your client boundaries sit and what they pull into the bundle. That single review usually identifies the largest available improvement.

How FISTA Solutions helps

FISTA Solutions builds and operates production systems through web and mobile, AI enablement, and staff augmentation: client boundaries placed to keep bundles small, caching behaviour stated explicitly rather than inherited from defaults, decisions documented with their reasoning, and handover that leaves your team able to maintain what was delivered. The record is 150+ projects for 50+ companies across 12+ countries.

To scope this work, message FISTA on WhatsApp, or read core web vitals guide.

Share-ready article cover

Download the generated social format.

Download cover

Clear answers

Questions raised by this field note.

Straightforward guidance for evaluating scope, fit, and the next step.

01What actually changes with the App Router?

Components render on the server by default, data fetching moves into components rather than into page-level functions, layouts persist across navigation, and several caching layers apply automatically. Client interactivity becomes an explicit boundary.

02Why is caching the main source of surprises?

Because several layers apply at once — request memoisation, the data cache, the full route cache, and the router cache — and the defaults have changed between versions. Stale data in development or production usually traces to one of them.

03What determines bundle size?

Where the client boundary sits. Everything below a client component ships to the browser, so a boundary placed high in the tree pulls in far more than intended. Pushing it down is the main optimisation.

04Does streaming help?

Meaningfully, for perceived performance. Rendering the shell immediately and streaming slower sections improves time to first content substantially, which is what users judge responsiveness by.

05How should migration proceed?

Route by route, with both routers coexisting. Wholesale migration converts every incompatibility into a blocking problem at once, whereas incremental migration surfaces them one at a time.

Start with the hard problem

Need the outcome owned, not merely analyzed?

Tell us where delivery is constrained. We’ll map the fastest credible path from intent to verified production.

Start a project