Questions
27 of 33
1Explain server-side rendering (SSR) in Next.js.
2List the benefits of Server-Side Rendering in Next.js.
3What are server components?
4How to use server components in next js?
5What is the React Server Component Payload (RSC)?
6Describe how server components are rendered.
7Describe server rendering strategies
8How can you keep Server-only Code out of the Client Environment
9What are the issues of using context provider at the root of the application?
10List dynamic functions available to server components.
11List all Dynamic APIs.
12How do we opt for Static Rendering, Dynamic Rendering and Streaming?
13Explain the difference between SSR, SSG, ISR, and CSR in Next.js. When would you choose each?
14How does getServerSideProps work internally? What is its execution context?
15What are the performance trade-offs of SSR vs SSG in a high-traffic production app?
16How does Next.js handle hydration? What is a hydration mismatch, and how do you debug it?
17What happens when getServerSideProps throws an error? How do you handle it gracefully?
18How would you architect a Next.js app that needs both personalised (SSR) and cacheable (SSG) pages at scale?
19Explain the App Router vs Pages Router SSR model differences. How does React Server Components change the SSR paradigm?
20How do React Server Components (RSC) differ from traditional SSR? Can they be used together?
21How does streaming SSR work in Next.js 13+? What role does Suspense play?
22How would you implement partial hydration or Islands Architecture in Next.js?
23Explain how Next.js handles data fetching waterfall problems in SSR and how you'd mitigate them.
24How would you implement partial hydration or Islands Architecture in Next.js?
25How do you implement caching strategies for SSR responses in Next.js? (CDN, Cache-Control, stale-while-revalidate)
26How would you reduce TTFB (Time to First Byte) in an SSR-heavy Next.js app?
27What's the difference between fetch caching in the App Router vs traditional getServerSideProps?
28How do you avoid redundant database/API calls across multiple server components on the same page?
29How do you securely handle authentication in SSR? What are the risks of passing tokens via cookies vs headers?
30How do you prevent sensitive server-side data from leaking to the client bundle?
31How would you implement role-based rendering on the server without exposing protected routes to the client?
32How do you debug SSR-only issues that don't appear in local development?
33How can we control dynamic rendering behaviour in next js?
27 / 33

What's the difference between fetch caching in the App Router vs traditional getServerSideProps?

App Router replaces getServerSideProps with per-component fetch caching, where data fetching is integrated directly into components and controlled by cache options, while Pages Router required a separate function that ran on every request without built-in caching

The shift from Pages Router to App Router represents a fundamental change in how data fetching and caching work in Next.js. In the Pages Router, getServerSideProps was a special function that ran on every request, separate from your component logic, and had no built-in caching mechanism—developers had to manually implement caching via Cache-Control headers or external CDNs. In contrast, the App Router integrates data fetching directly into Server Components using the native fetch() API, with granular caching controls that unify static and dynamic rendering under a single, flexible model. This moves from a "function-based" to a "declarative caching" paradigm where rendering strategy is determined by cache options rather than separate data-fetching methods.

Core Conceptual Differences
  1. 1

    Location of data fetching: Pages Router required data fetching in separate functions (getServerSideProps, getStaticProps) outside components; App Router allows direct async/await fetching inside Server Components.

  2. 2

    Default behavior: getServerSideProps always runs on every request; App Router's fetch defaults to 'force-cache' (static) unless explicitly configured otherwise.

  3. 3

    Granularity: Pages Router operated at page level—one function per page; App Router operates at component level, allowing different caching strategies within the same page.

  4. 4

    API design: Pages Router used special Next.js functions; App Router uses standard Web fetch() API with Next.js extensions for caching.

In the Pages Router, getServerSideProps was the primary mechanism for Server-Side Rendering. It ran on every request, executed on the server, and returned props that were passed to the page component. Critically, it had no built-in caching—each request triggered a fresh execution, and caching had to be implemented manually by setting Cache-Control headers on the response object. This meant developers needed to understand both Next.js and HTTP caching headers to optimize performance. The function also couldn't be used inside components, forcing all data for a page to be fetched upfront, which could create request waterfalls.

Pages Router: getServerSideProps Example

The App Router completely reimagines this model by making Server Components the default and integrating data fetching directly into components using the native fetch API. Instead of separate functions, you write async components that fetch data directly. The caching behavior is controlled through fetch options, unified across static and dynamic rendering. This means the same fetch API can produce SSG (with 'force-cache'), SSR (with 'no-store'), or ISR (with 'next.revalidate') behavior, all determined by cache options rather than function names.

App Router: Fetch Caching Examples

Under the hood, App Router introduces a sophisticated four-tier caching system that works together with fetch options. Understanding this architecture explains why fetch caching behaves differently from getServerSideProps . The layers are: Request Memoization (deduplicates fetches within a single render), Data Cache (persists fetch responses across requests and deployments), Full Route Cache (caches rendered HTML and RSC Payload), and Router Cache (client-side cache for instant navigation). When you set cache: 'no-store', you bypass all these caches. When you use next: { revalidate }, you enable ISR-style background updates across the Data and Route caches.

Cache Options Comparison Table

A crucial distinction that catches many developers off guard is the default behavior. In Pages Router, getServerSideProps is always dynamic by default—you must explicitly opt into caching via headers. In App Router, fetch() defaults to 'force-cache' (static) in Server Components, meaning your page might be statically generated unless you specify otherwise. This changed in Next.js 15, where the default fetch cache was adjusted, but the principle remains: App Router optimizes for static by default, while Pages Router optimized for dynamic by default. This is why you might see pages that were dynamic in Pages Router becoming static in App Router without explicit configuration.

When to Use Each Approach
  1. 1

    Use Pages Router when: You're maintaining a legacy application, need simplicity for small projects, or prefer the explicit separation of data fetching and rendering.

  2. 2

    Use App Router when: You need fine-grained caching control, want to reduce client JavaScript with Server Components, require streaming SSR, or need component-level data dependencies.

  3. 3

    For new projects, App Router is recommended as it represents the future direction of Next.js, with ongoing improvements like Partial Prerendering (PPR) and the new 'use cache' directive .

If you're migrating existing getServerSideProps pages to App Router, the equivalent is typically a Server Component with cache: 'no-store'. However, you should evaluate whether you truly need per-request freshness. Many pages that used getServerSideProps in Pages Router were actually good candidates for ISR or even static generation. The App Router model encourages you to think in terms of caching strategy rather than rendering method, often leading to better performance with the same data freshness.

Migration Example

Next.js is evolving toward an even more declarative model with the experimental 'use cache' directive and dynamicIO flag. This new approach lets you mark components or functions as cacheable, with automatic dependency tracking and cache tagging. It builds on the foundation of fetch caching but extends it to any asynchronous operation, including database queries. While still experimental, this represents the future of caching in Next.js, moving beyond fetch-specific caching to general-purpose component and function caching.