Dashboard

How to Add Server-Side Rendering to an AI-Built App

Most AI-built apps ship fully client-rendered, invisible to search crawlers and link previews. A scoped, route-by-route path to server-side rendering.

Carlo Zuercher
Carlo Zuercher
Staff Engineer, Platform
19 September 20261 min read

Most apps that come out of an AI builder are client-rendered single-page apps: the server sends a nearly empty HTML shell, and JavaScript builds the actual page in the browser. That is fine for a logged-in dashboard nobody needs to find on Google. It is a real problem for any page you want indexed or shared, because search crawlers and link-preview bots see that empty shell, not your content. Adding server-side rendering means moving the initial HTML generation to the server so the first response already contains the real page, then letting the client take over for interactivity after that.

Why AI builders default to client-rendered output

Client-side rendering is simpler to generate and simpler to preview instantly, which is exactly what an AI builder optimizes for during the build-and-iterate loop. The generated app is typically a single-page app framework talking to an API, with no server rendering step in between. That architecture works well right up until a page needs to rank in search or needs to render correctly when pasted into a chat app that fetches a link preview, both of which depend on the HTML actually containing content on first load.

Where SSR is worth the effort and where it is not

Page type

Needs SSR

Reasoning

Marketing and landing pages

Yes

These exist specifically to be found and shared

Blog or content pages

Yes

Search visibility is usually the entire point

Logged-in dashboard

No

Never indexed, never shared as a link preview, SSR adds cost with no benefit

Public profile or listing pages

Usually yes

Often shared as links and worth appearing in search

Rendering everything server-side when only a handful of pages need it is wasted engineering effort and can make the app feel slower for the logged-in pages that never needed it in the first place. Scope the work to the pages where it actually matters.

The migration path without a full rewrite

1. Identify the framework's rendering options first

Most modern frontend frameworks that AI builders generate code in already support a server-rendering mode, it is usually just not enabled, because the default scaffold optimizes for the fastest possible preview. Check whether the generated app already sits on a framework with a built-in SSR or static-generation mode before assuming a rewrite is needed. Enabling an existing capability is a day of work; bolting SSR onto a framework that fundamentally does not support it is a much bigger project.

2. Convert the specific pages that need it, not the whole app

Route-by-route conversion, starting with the highest-value marketing or content pages, keeps the blast radius small. Each converted route needs its data-fetching logic moved to run on the server before the first render instead of after the page mounts in the browser, which is usually the actual code change, more than the rendering mode switch itself.

3. Handle the hydration mismatch

The most common bug in this migration is a hydration mismatch: the server renders one thing, the client re-renders something slightly different on mount, usually because of a value that differs between server and browser, like the current date, a random ID, or anything reading from browser-only storage during the initial render. The fix is deferring any browser-only value to after the first client render completes, never computing it during the render that has to match the server's output.

4. Verify with the raw HTML, not the rendered page

Load the page with JavaScript disabled, or fetch the raw HTML directly, and confirm the actual content is present in that response. Looking at the rendered page in a normal browser tells you the client-side rendering still works; it tells you nothing about whether the server response itself contains real content, which is the entire point of the exercise.

What this costs you

  • Slightly higher server load, since the server now does rendering work it previously skipped entirely.

  • A build and deploy process that needs to support a server runtime, not just static file hosting, if the app was previously fully static.

  • New categories of bugs (hydration mismatches) that a purely client-rendered app never has to think about.

These costs are worth paying for pages that need to be found. They are not worth paying for pages that will only ever be seen by a logged-in user who navigated there directly.

Where this fits the bigger picture

Server-side rendering is one lever in the broader SEO effort for an app that came out of an AI builder; how to do SEO for an AI-built app with no marketing budget covers the rest of that work, most of which does not require any rendering changes at all. On the architecture side, this kind of targeted, route-by-route change is exactly the sort of decision that the monolith vs microservices tradeoff for an AI-built app and how to migrate an AI-built app to a new database also wrestle with: change the minimum necessary, verify at every step, keep a way back. For the full picture of building an app with AI, see the app-building pillar guide.

FAQ

Does every AI-built app need server-side rendering?

No. If nothing needs to be found in search or shared as a link preview, client-side rendering is simpler and has no downside. Add SSR only for the specific pages where indexing or sharing actually matters.

What is a hydration mismatch and why does it happen?

It happens when the server-rendered HTML and the client's first render disagree, usually because something like the current time or a random value was computed during the render itself instead of deferred until after the page mounts. The framework detects the mismatch and either warns or re-renders, which can cause a visible flash of incorrect content.

How do I check if server-side rendering actually worked?

Fetch the page's raw HTML directly, with JavaScript disabled or via a plain HTTP request, and confirm the real content, not just an empty shell, is present in that response. That is what a search crawler sees, and it is the only reliable test.

How did this land?

About the author

Carlo Zuercher
Carlo Zuercher

Staff Engineer, Platform

Carlo works on the platform that turns prompts into running apps. He writes the engineering deep dives and the changelog notes worth reading.

Share

Get the next post in your inbox

One email a month. Product updates, engineering posts, and the best of Built with Swarmz.

I agree to receive emails about AI building tips and Swarmz product news. Unsubscribe any time.