CSR, SSR, Static Generation, and Framework Choice
Compare the content crawlers receive with CSR, SSR, and static generation. Examine Next.js build outputs and update methods, and verify that material for search and AI answers is actually delivered.
The same article on screen can come from different material received by crawlers
For Sunday opening information to appear, something must read the data and create HTML elements. If the browser does this, the server may initially send only a loading screen. Generating it on the server allows hours and closure dates to be included in the response body. This matters for SEO, GEO, and AEO because search and answer systems obtain usable material from that response and subsequent processing.
Below are the body sections of two ways to provide the same notice. The CSR example fills the body with JavaScript in the browser; the server-generated example includes the body through SSR or static generation.
<!-- Initial response when the browser fetches the body -->
<main id="guide">Loading the guide.</main>
<script src="/guide.js" defer></script>
<!-- Response with a server-generated body -->
<main><article>
<h1>Library Sunday Opening Information</h1>
<p>Open Sundays 10–17. Closed on the first Sunday and public holidays.</p>
<p>Effective from October 2026.</p>
<a href="/policies/opening-hours">Original opening-hours notice</a>
</article></main>
The first response has no closure date. It becomes available only after /guide.js runs and retrieves the required material. The second response already contains the answer, exception, effective date, and evidence link. An HTML-reading tool obtains them without assembling the screen further. Examine this difference first, then choose when to generate the body.
Receiving the body leads into search results and AI answers
Search systems process fetched documents into an index and select material matching a question. If the page does not deliver ‘closed on the first Sunday,’ that condition cannot be obtained from it. Including the body in the HTML response reduces dependence on successful JavaScript execution and additional API requests for that information.
Google executes JavaScript and can process CSR content too. This involves rendering after crawling; blocked resources or failed requests can leave content missing. SSR and prerendering provide core content in the response. Google also explains that not all bots can execute JavaScript. Google’s JavaScript processing
Generative answers using web material also need readable documents. Eligibility for indexing and snippet display is among the requirements for Google generative search. Fixing body delivery therefore helps search systems process documents that may become evidence for answers. Then check relevance to the question, sufficiency of facts and conditions, and actual source selection. Google generative-search requirements
For example, answering ‘Can I visit on November 1, 2026?’ requires both Sunday hours and the first-Sunday closure condition. Including only hours in the server body changes delivery but still leaves insufficient material for the answer. Rendering solves delivery; the copy supplies facts needed for a decision. Check each external AI service’s crawling and retrieval methods in its documentation and actual citation results.
CSR and SSR differ in where they read data and build the body
CSR (Client-Side Rendering) creates the screen in the browser. When content is fetched there, the sequence is HTML receipt → JavaScript download and execution → API request → paragraph creation. A failure at any stage may leave a loading screen or only part of the information.
SSR (Server-Side Rendering) reads data and builds HTML on the server receiving the request. Fetching a public notice on the server and creating h1, p, and a elements puts its title, conditions, and evidence into the response. The browser displays the received text and attaches required button behavior afterward.
In SSR, slow queries and server errors affect the response. If an infrequently changing notice need not be rebuilt for every request, static generation or caching may suit it. Choose based both on whether material can be read and on how quickly it must update.
Static generation builds HTML before requests arrive
SSG (Static Site Generation) creates HTML per route before visitors request it. For example, the build reads introductions and usage guides, generates HTML for each URL, and serves it through a CDN. There is no need to query the database and rebuild the same page on every visit. Titles, bodies, and links are in the HTML, so SSG shares SSR’s core crawling benefit.
Statically generated pages can include buttons and search fields. React attaches interactions such as event handling to prebuilt HTML; this is hydration. Separately check whether files on static hosting contain the body for each route. If every URL receives the same empty index.html and the browser fills the body, that content is still delivered through CSR.
Updating is an operational challenge for SSG. Editing a CMS article after a build does not automatically change the existing HTML. Rebuild and redeploy, or connect regeneration of that route in a supported runtime. ISR (Incremental Static Regeneration) regenerates prebuilt pages under defined conditions or update requests. Connect revalidation APIs to publication events according to the Next.js version and cache settings in use.
Time-based updates may leave old articles visible in the interval. If withdrawal or access changes must apply immediately, design cache invalidation and request-time publication checks rather than waiting only for expiry. Background regeneration may serve the previous response while updating, so inspect the first request immediately after publication or withdrawal too.
A Next.js build prepares route-specific HTML and server code
A build transforms source code into deployable output. A typical React SPA build creates JavaScript and an HTML entry point and may leave the browser to fill the body. Next.js prepares pregenerated HTML and request-time server code according to route data fetching and settings. Both builds can succeed, so inspect when the page’s body enters the result.
In the later Next.js implementation exercise, /archive/opening-2025 generates a fixed historical notice at build time, while /guides/[slug] reads the current published revision for each request. The production server serves existing HTML for the first route and runs server code to produce the second response. Both can send content to crawlers, but changes take effect at different times.
A static route keeps serving the copy used during the build and must be regenerated after edits. A request-generated route can read new material with a new request, but any query cache must also update. After a build, check the generated routes, actual HTML, and content of the first response after an edit.
With output: export, Next.js creates deployable HTML, CSS, and JavaScript in the out directory. A static server can serve these files. Features that run server code per request and ISR are configured in deployments with a server runtime. Next.js static exports
Locate data fetching and HTML output in the example files
React is a library for composing interfaces from components, reusable units such as headings or article lists. JSX describes interface structure inside JavaScript using HTML-like notation. TypeScript adds types to JavaScript to check data shapes. tsx files combine TypeScript and JSX.
A build transforms and bundles written code for its execution environment. A bundle is the resulting combined code file. A development server shows changes quickly; a production build makes the actual deployable output. The runtime executes that output, with browsers and servers running their respective code.
Next.js App Router maps URLs to pages through the app directory structure. page.tsx defines the page at an address, layout.tsx shared structure, and route.ts an HTTP request handler. [slug] is the variable part of an address. In /guides/opening-hours, opening-hours is the slug. Some repositories use src/app.
generateMetadata creates titles, descriptions, and canonical URLs from page data. An API (Application Programming Interface) is a defined interface through which programs request data or operations. A public page’s server function can read the database directly or call an internal API. Apply publication conditions on the server without sending database credentials to the browser.
import brings in code from another file; await waits for an asynchronous result. useEffect runs additional work after the component is reflected in the browser. Fetching public content only in useEffect can produce the loading-only response shown earlier. Reading material in a server page and outputting it in JSX p elements can include it in the server-generated body.
Even with Next.js, trace where the body is generated
App Router pages and layouts are Server Components by default. They can read data on the server, with execution timing determined by static-generation and cache settings. Server Component describes an execution boundary; SSR and SSG describe when HTML is generated.
A component marked use client can also have its HTML prerendered on the server for the initial page load. Check whether core content appears only after useEffect, is hidden behind browser-only conditions, or has server rendering disabled for its area. The Server and Client Component explanation helps identify when data arrives.
If public articles are fetched only in an effect, move fetching to the server page and render the current published title, body, and sources. Isolate only interactions such as likes, sharing, and filters into small Client Components. Check that empty browser initial state does not overwrite the body received from the server. Also test for sentences that appear on the server but disappear after hydration.
Separate the CMS editor’s working draft from its published revision, and let body and metadata read the same public version. Moving rendering while fetching a temporary draft can expose private copy in an attempt to fix search. Select the current published revision in the public-query function, then pass it to body and metadata.
Compare server-rendering setups in Vite and Next.js
Vite is a development server and build tool. An SPA (Single-Page Application) switches views with JavaScript inside one document. A typical Vite-based React SPA builds application JavaScript and an HTML entry point. Fetching articles with useEffect in that setup leaves per-page body generation to the browser. If route-specific HTML, canonical URLs, and a sitemap are needed, configure server rendering or pregeneration and metadata generation.
Vite also supports SSR. Configure a server entry point to render components and insert the result into HTML, or use a Vite-based SSR or static-generation framework. Request handling, data fetching, per-route head content, 404s, redirects, caching, and updates still require choices. Vite’s SSR guide explains its low-level APIs and server and client entry points.
Next.js provides a broader application structure. App Router pages and layouts, server data fetching, static and dynamic rendering, Metadata API, robots and sitemap conventions, redirects, and deployment runtimes can be managed within one structure. For example, after fetching a CMS revision, the body, generateMetadata, and JSON-LD can use the same material, with relevant caches updated on publication changes.
This integration can justify choosing it for a site that pregenerates introductions and archival material, reads current published revisions for new articles, and supplies a title, canonical URL, and source for every detail page. Routes, metadata, sitemaps, and server responses remain easier to trace in one application after redesigns. It can reduce omissions caused by separate implementations of publication conditions. Search systems collect the HTML, links, and metadata produced by this structure.
A Vite-based setup can provide the same public HTML, metadata, status codes, and updates. Compare how much routing, server-query, and cache code must be implemented, what the deployment environment supports, and the team’s maintenance experience. Start by checking whether an existing stable setup already meets these requirements.
Generating titles, bodies, and canonicals for hundreds of CMS guides in separate code paths makes omissions more likely when adding a content type. A practical reason to choose Next.js is managing route queries, Metadata API, and sitemap generation through the same data and file structure. Evaluate whether this reduces omissions and inconsistencies in actual output. Existing Vite SSR or other server setups providing the same responses and update behavior meet the requirement too.
Choose generation timing and updates per page
Introductions or archived guides that do not change between deployments can be statically generated. Detail articles regularly published and withdrawn in a CMS must read the current published revision at request time or update caches on publication events. Personalized admin screens first handle authentication and per-user data.
These methods can coexist on one site. For each URL type, define generation timing, acceptable stale-content duration, and failure responses. An SSR page can also stream shared structure first and data later.
If the response starts only after a server query completes, that wait is included in time to first byte. If the shell is streamed first, body fetching may finish after the first byte. Measure both first-byte time and actual body-display time.
Compare before-and-after HTML, then actual search processing
After completing the exercise’s installation and execution steps, run the commands below and save the complete responses for both URLs. curl does not execute JavaScript, so it does not fetch articles the browser later requests and inserts.
curl -sS -D current.headers -o current.html http://localhost:3027/guides/opening-hours
curl -sS -D archive.headers -o archive.html http://localhost:3027/archive/opening-2025
In current.html, find opening hours, the first-Sunday closure, and the effective date. In archive.html, find the 2025 validity period and link to current guidance. The HTML parser checks distinguish text present only in script data and compare article content, links, and dates. With streaming, read both the complete response and the browser’s finished DOM.
Next, edit the CMS data or fixed exercise copy and request the same addresses again. Static pages should show the new sentence after rebuilding; request-generated pages after a new request and necessary cache updates. This verifies whether the selected method meets actual update requirements.
After applying the change in production, inspect Search Console’s crawl and rendering results and last crawl date. Ask web-search-enabled AI the same question with the same reference date and inspect the cited URL and closure conditions. Compare in order whether the server response has the new sentence, search processed the new document, and the answer used that condition to narrow down the next fix.
When SSR-generated HTML contains an img, the browser discovers its address and makes a separate image request. Even if opening hours are immediately in the HTML, a 5MB original image still requires transfer and decoding. That is why CMS photos’ currentSrc and response bytes must be checked even after a successful Next.js build. The CMS image-delivery exercise keeps HTML generation fixed and compares only original-file versus derivative requests.