Halloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowHalloween DealsAmazon USOctober picks are moving - compare before checkoutAmazon US: current deals, useful picks and tech finds.See Picks×
FREEDOM251

Freedom251 › Blog › client-only rendering

How to migrate a React app to client-only rendering without breaking routing or hydration

By Freedom251 Team · · 11 min read

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Client-only rendering is a delivery change, not a one-line API swap. First inspect the HTML your browser receives: if it already contains markup produced by React on a server or at build time, keep hydration with hydrateRoot; if the mount element is genuinely empty, render with createRoot. Then move route data deliberately, configure your host to send the SPA entry for deep links, and test the first render, navigation, refreshes and APIs separately.

What “client-only rendering” actually changes

A client-rendered app sends a document and JavaScript to the browser, then lets JavaScript build the React tree. That differs from runtime server-side rendering (SSR), where each request can receive route-specific HTML, and from build-time rendering, where HTML is generated during a build and shipped as a static file.

As an Amazon Associate I earn from qualifying purchases.

The important distinction is the DOM that exists when React starts. React has two different contracts:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Initial DOM condition API What React does What you must preserve
The root has no React-generated markup createRoot Creates a client root and clears existing content in that root on its first render A mount element and JavaScript capable of rendering the app
The root contains markup generated by the same React tree on the server or at build time hydrateRoot Attaches event handlers and React state to the existing HTML Matching output for the server/build render and the first client render

React documents the API distinction in createRoot and hydrateRoot. Calling createRoot over server HTML can remove that markup and reset interaction state such as focus or scroll. Calling hydrateRoot on an empty or unrelated element cannot hydrate anything useful.

#1 Best Overall
Sale
TOZO A1 Wireless Earbuds Bluetooth 5.3 Light Weight in Ear Headphones | IPX5 Waterproof,2 Mics for AI Calls,Immersive Premium Sound Bass Headset with Charging Case,32 EQ via App Black
  • [Ultra-Lightweight Ear Buds Designed for Small Ears] Each earbud weighs only 3.7g and features a compact, ergonomic in-ear design made especially for small ears. Secure, low-profile, and comfortable for workouts, all-day wear or overnight sleeping.The ultra-slim profile sits flush in your ear with no hard edges poking or rubbing, so you can even sleep on your side without discomfort.
  • [Immersive Stereo Sound with TOZO OrigX Technology] TOZO OrigX tuning delivers clear vocals, balanced mids, and natural stereo sound for music, podcasts, and videos.
  • [Long Battery Life for Daily Use] Get up to 7 hours of playtime on a single charge, with up to 32 hours total using the charging case—ideal for workdays, commuting, and extended listening sessions.
  • [Bluetooth 5.3 & Stable Connection] Bluetooth 5.3 provides fast pairing, stable wireless performance, and reduced dropouts as you move around home or office.
  • [Deep Bass with Clear Vocals] High-performance drivers produce punchy bass while keeping vocals clean and detailed for everyday listening.

“Client-only” also does not mean “routing is disabled.” A client router still reads the browser URL, chooses a route, renders links and handles back/forward navigation. What changes is where the initial document and route data come from.

Start with an inventory of the delivered HTML

Do not infer the rendering mode from component code. A component that uses window may still be rendered on a server if that branch is deferred or guarded. Inspect the actual response and the framework entry point before changing it.

  1. Load the application URL with JavaScript disabled or fetch the document with a tool such as curl. Find the element used as the React mount point, commonly an element with an id such as root.
  2. Classify the contents of that element. Meaningful page markup, headings or route content indicate server or build output. An empty element with only a script reference indicates a client bootstrap.
  3. Record route behavior. Test the home page, a nested URL, a direct refresh of that nested URL, an unknown path and any API paths. Note which pages are server-rendered, statically generated or rendered only after JavaScript runs.
  4. Identify the owner of the entry point. A hand-built app, a bundler template and a framework-controlled entry file have different migration steps. In React Router Framework Mode, the browser entry convention is documented at entry.client.tsx; do not replace that file with a generic snippet without checking the framework.

Capture a copy of the current HTML and the data used for the first render. You will need both when diagnosing a hydration warning later.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose the correct root API

Use createRoot for a genuinely empty root

For a hand-built client app whose HTML contains an empty mount element, the browser entry can render the application directly:

import { createRoot } from 'react-dom/client';
import App from './App';

const element = document.getElementById('root');
if (!element) throw new Error('Missing root element');

createRoot(element).render(<App />);

The first render replaces the root’s existing contents. That is correct only when those contents are a placeholder that React is supposed to own. If a server template puts meaningful content, an accessibility announcement, or interactive elements in the same root, moving to createRoot discards them.

Keep hydrateRoot when React-generated HTML remains

If the response includes HTML produced from the matching React tree, retain hydration:

Rank #2
Sale
Smart Watch for Men Women Compatible with iPhone Samsung Android Phone 1.69 inch Full Touch Screen IP68 Waterproof Bluetooh Fitness Tracker Heart Rate/Sleep Monitor (Black)
  • 【IP68 Waterproof Multifunctinal Smart Watch】Torjalph fitness activity tracker smart watch is IP68 waterproof technology ,you can wear it when swimming,handwashing,it's rain-proof which means that you perform multiple exercise modes outside without worrying about sweat or rain corroding your fitness smart watch,and this watch equipped with a 230 mAh large capacity battery magnetic charging ,and this sports activity tracker watch can be used 5-7 days If fully charged.
  • 【Larger 1.83'' Full Screen Watch & Multi-dial Selection】1.83 inch full HD color touch screen smart watch for men / women provides excellent 240*284 resolution image quality ,This Bluetooth smart watch offers a better touch experience and remarkable immersion and ,more than 200 watch faces for you to choose from App"Da Fit ", you can change the dial style according to your mood to wear keeping the world on your wrist
  • 【Accurate Activity Tracker Smart Watch 】sports watch activity tracker uses sweat and dust resistant breathable silicone strap, our Fitness Tracker Smart Watch for Android iOS Phones supports 12 sports modes,walking,running,bicycle,swimming,badminton,basketball,football,rope skipping. This bluetooth calls smart watch for men women is lightweight and stylish, bringing more convenient and relaxing sports experience while also providing more protection.
  • 【Your 24 Hour Personal Daily Health Monitor】Fitness watch for women men full touch screen IP67 waterproof bluetooth smartwatch for Android iOS Phones with heart rate blood pressure monitor multifunction Andriod smart watch with steps counter sleep monitor sports fitness watch, monitoring blood oxygen saturation allows you to understand your physical condition in real time to track fitness progress ,to know your health status in time.
  • 【More Functions Bluetooth Call Smart Watch】This fitness activity smart watch full screen for iPhone and Android phones includes a bunch of new features including:The bluetooth smart watch can hang up the phone, receive and display WhatsAPP /Text /Facebook /Twitter /Messenger reminder.Support sedentary reminder, alarm clock, stopwatch, timer,weather information,music control, remote camera control compatible with Android 5.0 and above or iOS 9.0 and above smartphones.
import { hydrateRoot } from 'react-dom/client';
import App from './App';

const element = document.getElementById('root');
if (!element) throw new Error('Missing root element');

hydrateRoot(element, <App />);

Hydration is not a slower form of client rendering. It is an agreement that the initial client tree describes the existing HTML. React expects the same element structure, text and attributes before it takes over.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Do not mix the two decisions accidentally

A page can contain a static shell outside the React root and still use createRoot inside an empty mount point. Conversely, a build-generated root document still needs hydrateRoot even though no request-time server rendered it. Decide per root and per delivery path, not by searching for a single “SSR” switch.

Make the first render deterministic wherever hydration remains

React’s hydration reference says to treat mismatches as bugs and fix them. A mismatch can force React to abandon parts of the server tree, produce incorrect attributes or replace the DOM, undermining the reason for sending HTML in the first place. Common causes listed in the React documentation include:

  • A typeof window branch that produces different markup on the server and browser.
  • Reading browser-only APIs, such as localStorage or viewport measurements, during render.
  • Different data snapshots between the server/build render and the first client render.
  • Formatting dates, numbers or text with a locale or time zone that differs between environments.
  • Invalid HTML nesting that browsers repair differently from React’s tree.
  • Third-party extensions or scripts that modify the document before hydration.

Move browser-dependent work into an Effect or otherwise render a stable first pass. A two-pass pattern can deliberately render the same placeholder first and replace it after hydration:

function Clock() {
  const [client, setClient] = useState(false);
  useEffect(() => setClient(true), []);

  return <span>{client ? new Date().toLocaleTimeString() : '—'}</span>;
}

This avoids a mismatch, but it adds another render and can make the transition visible. Use it for genuinely client-specific output, not as a blanket fix. React describes suppressHydrationWarning as a limited escape hatch for unavoidable differences; applying it broadly hides defects instead of making the trees correct. See the hydrateRoot caveats and React’s production hydration error guidance.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Using React Router Framework Mode as an explicit SPA example

React Router Framework Mode has a documented SPA setting, but it is not a universal React or router API. In that mode, setting ssr: false disables runtime SSR. The build emits an index.html that contains the root document, and the browser hydrates that document as an SPA.

Rank #3
New Bee Guitar Cable 10ft Electric Instrument Bass AMP Cord | 6.35mm Jack, Durable Design, Stage and Home Studio Use, Low Noise Shielded Electric Cord for Bass, Keyboard, Amp, Mixer
  • [Low Noise High Fidelity] New bee guitar cord with 22AWG oxygen-free-copper center conductors provides enhanced signal transfer, the PVC insulation material and the high-density stranded copper double shield provide noise rejection for quiet operation
  • [Ideal for Choice] New bee 1/4 straight and right angle metal connectors, ensures a secure connection in any instrument, pedal, or amp jack. L shape great fro on stage guitar stands
  • [Wide Compatible] Suitable for mixer, power amplifier, microphone, effector, decoder, equalizer, electoronic organ, electric guitar, electric bass and other electronic equipments. Widely used in the installation of smart home, karaoke speaker, professional stage audio, etc
  • [Easy Disassemble] Making incidental repairs quick and easy! Very nice, flexible cable
  • [Dont Hesite to Order] 24 hours customer services and professional technology team are standing by
import type { Config } from '@react-router/dev/config';

export default {
  ssr: false,
} satisfies Config;

With SPA Mode enabled, the root route is rendered into the generated document. During hydration, the browser URL determines which child route the application displays. A request to /settings still needs to receive the SPA entry; the router cannot run if the host returns a file-system 404 before JavaScript loads.

Provide an initial shell when an empty root would be blank

A purely client-rendered root can show a blank area until the JavaScript bundle downloads and executes. React Router allows a root HydrateFallback for content that should appear in the generated HTML while the application hydrates:

export function HydrateFallback() {
  return (
    <main aria-busy='true'>
      <h1>Loading application…</h1>
    </main>
  );
}

The fallback is a loading shell, not server rendering of every child route. It does not make private data available in the document or remove the need to plan route data. Root loader data can be produced at build time where the framework supports it; pages that need request-specific data require another strategy.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Plan route data and mutations separately from rendering

Changing the document delivery does not automatically move route data into the browser. In React Router SPA Mode, ordinary non-root route loaders are generally unavailable for routes that are not prerendered. The documented client-side alternatives are clientLoader for reads and clientAction for mutations; see the Client Data guide.

Classify every route’s data

  • Build-time data: stable navigation labels, public configuration or content that can be embedded into the generated document.
  • Browser-fetchable data: data that can be requested after JavaScript starts through clientLoader or ordinary browser fetches.
  • Prerendered data: public pages that should have HTML before JavaScript and can be generated for known paths.
  • Request-specific server data: personalized, secret or frequently changing data that may justify retaining runtime SSR or adding an API/backend.

Check security and network assumptions

A browser-side loader exposes its request to the user’s browser. Verify authentication and authorization, cookie or token handling, CORS policy, CSRF protections and whether the API is allowed to reveal the requested fields. The React Router BFF example assumes authentication is handled correctly and that CORS does not block the browser request; those assumptions are not automatic.

Do not put server credentials, database access or private environment variables into a client bundle. If a route needs a server-only secret, keep a server endpoint, use a backend-for-frontend, prerender only non-sensitive content or retain SSR for that route.

Rank #4
BSIMB 15.6" Digital Family Calendar & Chore Chart, No Subscription Fees
  • Digital Family Calendar: BSIMB digital calendar wall touch screen puts an end to your chaotic life. Designed for busy families, the digital calendar keeps you organised and in step with your family. Assign different colours and tasks to each family member to make family scheduling easier and more intuitive.
  • Easy Setup and Auto-Sync: Plug in, connect to WLAN and auto-syn your electric calendar in minutes. Digital wall calendar compatible with Google calendar, iCloud calendar, Outlook calendar, Cozi calendar and Yahoo calendar. Add events directly on the device or through the ecalendar app. Electronic calendar stays current whether you're at work or traveling—no manual updates needed.
  • All-In-One Home Assistant: Smart calendar builds habits and encourage independence with personalised chores. Display daily meal plan to reduce the daily ‘What's for dinner?’ stress. To-do lists keep track of everything you want. Turning chores into valuable achievements with stars and rewards, making life easier and more enjoyable.
  • Manage Anytime Anywhere: BSIMB electronic calendar for family stay connected with the powerful ecalendar app. Access and manage your digital wall calendar anytime, anywhere with free features like stars & rewards, photo screensaver, chore charts, meals plans, to-do lists etc. Electronic planner paid features like Magic Import tailor advanced tools for users with special needs.
  • Stay in Touch with Loved Ones: Share photos or videos from your phone to electronic wall calendar with app, instantly update your life moment, and keep in touch with your family, especially those who are far away; you can also surprise your smart calendar digital wall by sending him a wish card; it's also great for keeping tech-illiterate elders in touch with the youngsters.

Decide whether data must exist before navigation

Client data can produce a loading transition after a navigation. If a page must be indexable, visible with JavaScript disabled or complete before a user sees the route, assess prerendering or continued SSR rather than forcing every page into a client fetch. React Router’s Pre-Rendering documentation describes combining SPA behavior with selected generated routes.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Configure hosting so deep links reach the SPA entry

Static hosting normally maps a URL to a file. A client route such as /account/billing is not a file, so a direct request can return 404 even though clicking to that route works after the app is loaded. React Router’s SPA guide states the general rule: direct all application URLs to the client build’s index.html.

Use your host’s documented rewrite or fallback rule to send valid application paths to the SPA entry. The exact syntax differs by host, so do not copy a rule intended for another platform. Keep these exceptions intact:

  • JavaScript, CSS, images and other static assets must continue to resolve to their real files.
  • API paths must reach the API service rather than the SPA document.
  • Health checks, robots files and verification files should retain their intended responses.
  • Unknown application paths should follow your router’s 404 route; decide whether the host fallback should send them to the SPA so the app can render that 404.

After deployment, open a nested URL in a new private window and press refresh. This tests the host fallback without relying on an already-loaded client router.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

A migration sequence that limits risk

  1. Capture a baseline. Save the current document HTML, first-paint behavior, route transitions, form submissions, console output and direct-request results for representative routes.
  2. Inventory the root and entry owner. Confirm whether the mount node contains React-generated markup and whether a framework controls the browser entry.
  3. Select the root API. Use createRoot only for an empty root. Keep hydrateRoot for matching server/build markup.
  4. Stabilize the initial tree. Remove browser-only reads from render, align data snapshots and fix invalid nesting before changing deployment.
  5. Enable framework SPA mode deliberately. In React Router Framework Mode, set ssr: false, add a root fallback if an initial shell is needed, and identify routes that require prerendering.
  6. Refactor data paths. Move suitable reads and mutations to clientLoader and clientAction; provide an authenticated, CORS-compatible API for them.
  7. Install the host fallback. Rewrite application paths to the SPA entry while preserving assets and APIs.
  8. Build and deploy a staging version. Test with production-like asset paths, compression, caching and environment variables.
  9. Exercise every navigation mode. Test in-app links, direct opens, refreshes, back/forward buttons, unknown routes, slow networks, failed API calls and submitted forms.
  10. Compare user-visible behavior. Check the loading shell, focus and scroll restoration, route transition timing, hydration console messages and the content available before JavaScript.

Rendering choices and their trade-offs

Choice Direct URL and refresh Content before client JavaScript Data availability Operational cost
Single client-only SPA Works when the host rewrites application paths to the SPA entry Only the document shell or fallback; the root can otherwise be blank Browser fetches, client loaders and build-time data Static hosting is simpler, but fallback and API rules must be correct
SPA with selected prerendered routes Generated paths can be served directly; other paths still need the SPA fallback HTML for selected routes; shell or loading state elsewhere Build-time data for generated pages and client data for the rest Build and invalidation rules become more involved
Continued runtime SSR Server resolves each request and route Request-specific HTML can be sent before hydration Server loaders and request context remain available Runtime server infrastructure and its failure modes remain

These are architectural trade-offs, not measured performance results. React’s createRoot documentation specifically warns that an empty root can leave users staring at a blank page until JavaScript executes. Measure your own first paint, interaction readiness and route latency rather than assuming client-only rendering is faster.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Troubleshoot the failures that appear after migration

The first screen is blank

Confirm that the JavaScript bundle loads, the mount element exists, the entry code runs and the root fallback is actually included in the generated document. Inspect network errors and Content Security Policy violations. If the root is intentionally empty, design a build-generated shell or prerender suitable routes instead of claiming the app is available before JavaScript.

Nested URLs return 404 on refresh

The host is serving files but not rewriting application paths to the SPA entry. Add the host-specific fallback, deploy it with the client build and retest a nested URL in a fresh browser context. Check that the fallback does not intercept assets or API paths.

React reports a hydration mismatch

Compare the saved server/build HTML with the first client output. Check time and locale formatting, random values, browser API branches, changed data, invalid nesting and extensions that mutate the page. Fix the differing render path; reserve suppressHydrationWarning for a narrowly understood unavoidable difference.

Markup or focus disappears

If existing root content vanished, the entry probably called createRoot where hydration was required. Restore hydrateRoot for that HTML or remove the server/build markup so the root is truly empty. Then retest focus, scroll position and any pre-hydration interaction.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A route has no data after switching to SPA Mode

Check whether it relied on a non-root route loader that is not available for a non-prerendered SPA route. Move browser-safe work to clientLoader or a fetch, expose a properly secured API, prerender the page or retain server rendering where the data must be available before JavaScript.

Loading behavior feels abrupt

A root HydrateFallback can provide a deliberate shell, but it does not eliminate hydration and client data work. Give the shell stable dimensions, expose busy state accessibly and test slow JavaScript and slow API responses so the transition is understandable.

Final launch checklist

  • The delivered root is classified as empty or React-generated, and the entry uses the corresponding API.
  • The first server/build and client trees use the same structure and initial data wherever hydration occurs.
  • Browser-only values are deferred intentionally, with no unexplained hydration warnings.
  • React Router SPA configuration is limited to the framework example where that framework is actually in use.
  • Every route has a documented data source: build-time, client-side, prerendered or server-side.
  • Authentication, CORS, CSRF and data exposure have been checked for browser requests.
  • The host rewrites application URLs, while assets, APIs and special files remain correctly routed.
  • Direct opens, refreshes, client navigation, back/forward, unknown paths and API failures have been tested in production-like conditions.
  • First paint, loading shell, focus, scroll, forms and route transitions have been compared with the previous deployment.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

client-only renderingfrontend migrationhydrationReactReact RouterSPA deployment

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.