Telerik blogs

How we handle navigation and URL changes in web apps plays a pivotal role in UX, performance and SEO. Let’s compare server-side routing and client-side routing.

In the realm of web development, the way we handle navigation and URL changes plays a pivotal role in user experience, performance and search engine optimization. Understanding the difference between server-side and client-side routing is fundamental for developers. In this article, we’ll delve into the specifics of these two popular routing techniques and compare their pros and cons.


First and foremost: let’s define routing for those who may be new to the concept.

In web development, routing often refers to splitting an application’s UI based on rules derived from the browser URL. Imagine clicking a link and having the URL go from to That’s routing.

When we visit the / path of a website, we intend to visit the home route of that website. If we visit /about, we want to render the About page, and so on.

Many applications can technically be written without routing but this can get messy as an application grows. Defining routes in an application is useful since one can separate different areas of an app and protect areas of the app based on certain rules.

Routing is often categorized into two main buckets:

  • Server-side routing
  • Client-side routing

Server-Side Routing

In a server-driven application, requests to a URL often follow a pattern:

  1. The client (i.e., browser) makes a request to the server for a particular page.
  2. The server uses the identifiers in the URL pathname to retrieve the relevant data from its database.
  3. The server populates a template (HTML document) with this data.
  4. The server returns the template along with other assets like CSS/images to the client.
  5. The client renders these assets.
  6. For subsequent route changes, the client again sends a new request to the server, and the above is repeated.

Server-side routing is often set up to retrieve and return different information depending on the incoming URL. Writing server-side routes with Express.js generally looks like the following:

const express = require("express");
const router = express.Router();

// define the about route
router.get("/about", function (req, res) {
  res.send("About us");

Or using Ruby on Rails, a similar route definition might look like this:

# routes.rb
get '/about', to: 'pages#about'

# PagesController.rb
class PagesController < ActionController::Base
  def about

Whether it’s Express.js, Ruby on Rails, or any other server-side framework, the pattern often remains the same. The server accepts a request and routes it to a controller, and the controller runs a specific action (e.g., returns specific information), depending on the path and parameters.

Client-Side Routing

In applications employing client-side routing, the server initially provides a single HTML file, irrespective of the URL path. This “shell” is then enriched and manipulated by JavaScript running in the browser. Subsequent navigation between different parts of the app does not send new requests to the server but rather modifies the displayed content based on the loaded JavaScript and data.

These are characteristic of single-page applications (SPAs)—web apps that load only once (i.e., the server provides a single template) and JavaScript is used to dynamically render different pages.

The flow for client-side routing usually looks like the following:

  1. The client makes an initial request to the server.
  2. The server responds with a primary HTML document (the single page of the SPA) and associated assets (e.g., JavaScript, CSS).
  3. The client interprets the JavaScript, and the app logic determines which content to display based on the URL path.
  4. For subsequent route changes, the JavaScript updates the browser’s history and displayed content without a full page reload.

With client-side routing, while the initial load might seem slower because the entire app (or large parts of it) gets loaded, subsequent navigations are swift and seamless, as they don’t require round-trips to the server.

Client-side routing can be implemented using various libraries and frameworks. For instance, React Router is a popular client-side routing library for React applications:

import * as React from "react";
import { createRoot } from "react-dom/client";
import {
} from "react-router-dom";

const router = createBrowserRouter([
    path: "/",
    element: (
        <h1>Hello World</h1>
        <Link to="about">About Us</Link>
    path: "about",
    element: <div>About</div>,

  <RouterProvider router={router} />

While for Vue applications, Vue Router is the recommended client-side routing library.

const Home = { template: "<div>Home</div>" };
const About = { template: "<div>About</div>" };

const routes = [
  { path: "/", component: Home },
  { path: "/about", component: About },

const router = VueRouter.createRouter({
  history: VueRouter.createWebHashHistory(),

Server-Side Routing vs. Client-Side Routing

Both server-side and client-side routing have their places in modern web development. The choice between them often comes down to the specific needs of the project.

In server-side routing:

  • The server only requests the webpage that the user is viewing, not the entire web app. As a result, the initial page load is often faster since we’re only downloading the content for one webpage (pro).
  • Search engines find it easier to index server-rendered applications. This can be a key factor for sites where search engine ranking is paramount (pro).
  • Every URL change results in a full-page refresh as the server returns the contents to the client. This is the unpleasant blinking state that’s shown to a user when a user navigates from route to route (con).
  • Templates that are to remain the same might have to be requested from the server over and over again (e.g., a header and a footer that stays the same on all webpages) (con).

While in client-side routing:

  • Since there isn’t a need to wait for a server response after the initial page load, navigating between webpages is often faster than server-rendered applications. Additionally, the white “blinking” state no longer exists when navigating from route to route (pro).
  • Since the template of the entire web app needs to be loaded on the first request, the initial page load time is often longer than server-rendered applications (con).
  • Search engine crawling is less optimized. With modern browsers, there is some good progress being made on crawling SPAs for search engines, but it isn’t nearly as efficient as server-side routed websites (con).

If search engine optimization and initial page load speed are critical, server-side routing might be the way to go. On the other hand, if the priority is to provide a dynamic, app-like user experience, then client-side routing in a SPA could be the ideal choice.

In today’s versatile tech landscape, hybrid solutions are also emerging that combine the best of both worlds, such as Next.js for React or Nuxt.js for Vue, which offer server-side rendering for SPAs, thus addressing many traditional drawbacks of client-side routing. We’ll talk about these frameworks in more detail in upcoming articles!

Ultimately, understanding the nuances, strengths and weaknesses of both the server-side and client-side routing methods will empower you to make informed decisions that best suit your application’s needs.

About the Author

Hassan Djirdeh

Hassan is currently a senior frontend engineer at Doordash. Prior to Doordash, Hassan worked at Instacart and Shopify, where he helped build large production applications at-scale. Hassan is also a published author and course instructor and has helped thousands of students learn in-depth fronted engineering tools like React, Vue, TypeScript and GraphQL. Hassan’s non-work interests range widely and, when not in front of a computer screen, you can find him at the gym, going for walks or running through the six.

Related Posts


Comments are disabled in preview mode.