Table of Contents

How we can convert client side rendering react js app to server side rendering using react router 4?

Transforming Client-Side Rendering React Apps to Server-Side Rendering with React Router As developers, we often start by building Single Page Applications...

2026-08-10

Transforming Client-Side Rendering React Apps to Server-Side Rendering with React Router

As developers, we often start by building Single Page Applications (SPAs) using client-side rendering (CSR), which offers a fast initial load experience inside the browser. However, for SEO benefits, improved performance metrics (like Core Web Vitals), and better initial load times, Server-Side Rendering (SSR) has become the industry standard.

The question of how to migrate an existing CSR React application, especially one utilizing react-router (v4 or later), to SSR requires a shift in architectural thinking. It’s not just about changing where the rendering happens; it’s about integrating the routing logic into the server environment.

Understanding the Shift: CSR vs. SSR

In a CSR setup, the browser downloads the JavaScript bundle, executes React, and then uses react-router to dynamically render components based on the URL history managed entirely on the client side.

In contrast, Server-Side Rendering (SSR) involves the server executing the React code, fetching necessary data, generating the full HTML string for a specific route, and sending that pre-rendered HTML to the client. This drastically improves initial load time and accessibility.

The Role of React Router in SSR

react-router itself is fundamentally a client-side library; it manages the state transitions within the browser environment. When moving to SSR, we need a mechanism to replicate this routing structure on the server before rendering the HTML.

The conversion process involves decoupling the routing logic from the pure client-side execution and integrating it into a Node.js server environment. We typically use libraries like ReactDOMServer to perform the actual server-side rendering of React components into an HTML string.

Step-by-Step Conversion Strategy

  1. Setup the Server Environment: You need a backend (e.g., using Express.js) running on Node.js to handle incoming requests and render pages.
  2. Integrate Routing Logic: Instead of relying solely on BrowserRouter in a client setup, you must define your routes on the server side. This often involves reading the request URL (req.url) and mapping it to the appropriate component structure.
  3. Server-Side Data Fetching: Since SSR requires data to be present before rendering, all data fetching (e.g., fetching posts for a specific route) must occur on the server before calling ReactDOMServer.render().
  4. Hydration: Once the HTML is sent to the browser, the client-side React application must "hydrate" this static HTML by attaching event listeners and making the application interactive.

Code Example: Conceptual SSR Setup

While a full, production-ready implementation is extensive, here is a conceptual look at how routing might be managed on the server side using a framework philosophy similar to what you might see when building robust APIs—similar to how modern backends handle complex data flow, much like systems built around frameworks like those in the Laravel ecosystem.

// Example: Conceptual Server-Side Rendering Logic (Node/Express)
  const React = require('react');
  const ReactDOMServer = require('react-dom/server');
  const Router = require('react-router-dom'); // Note: We adapt routing for server context
  
  // Assume this function simulates fetching data based on the route
  async function getRouteData(path) {
      // In a real app, this calls a database or external API
      if (path === '/') {
          return { title: "Home Page", content: "Welcome to the SSR App!" };
      }
      return { title: `Page: ${path}`, content: `Content for ${path}` };
  }
  
  app.get('/', async (req, res) => {
      try {
          const route = req.url;
          const data = await getRouteData(route);
  
          // 1. Render the React component tree to an HTML string
          const appMarkup = ReactDOMServer.renderToString(
              React.createElement(App, { routeData: data }) // App is the main component defined by router structure
          );
  
          // 2. Inject the rendered HTML into the response
          res.send(`
              <!DOCTYPE html>
              <html>
              <head><title>${data.title}</title></head>
              <body>
                  <h1>${data.title}</h1>
                  <p>${data.content}</p>
              </body>
              </html>
          `);
  
      } catch (error) {
          res.status(500).send('Server Error');
      }
  });
  

Conclusion: Embracing Full-Stack Rendering

Converting a CSR React application to SSR using react-router is more than just changing a few imports; it requires adopting a full-stack rendering mindset. You are moving from thinking purely client-side to managing the entire lifecycle—fetching data, structuring routes, and generating HTML—on the server.

While you can build this manually, for complex applications, leveraging established meta-frameworks (like Next.js or Remix) often provides the most robust and scalable solution, handling the complexities of hydration and routing automatically. However, understanding the underlying mechanism—how your routing structure translates into server-side data fetching and HTML generation—is crucial knowledge for any senior developer. This approach aligns well with building cohesive systems, much like ensuring data integrity across a full stack.

Stefan

Stefan

SEO engineer and Laravel developer. Building tools to help Laravel applications rank higher in search results.

Share this article

Back to Blog