# How the React Router Application Works in Plane’s Frontend: File-Based Routes, SSR, and MobX State Management

> Explore how Plane uses React Router v7 file-based routing, SSR with @react-router/node, and MobX for reactive URL state management in its frontend architecture.

- Repository: [Plane/plane](https://github.com/makeplane/plane)
- Tags: deep-dive
- Published: 2026-08-23

---

**Plane’s React Router application leverages React Router v7’s file-based routing in `apps/web/app/routes`, server-side rendering via `@react-router/node`, and a MobX `RouterStore` to manage reactive URL state across the project management interface.**

Plane’s open-source project management platform implements a modern React Router architecture in its `apps/web` package to deliver a fast, SEO-friendly user experience. The application uses the React Router v7 ecosystem—including `@react-router/dev`, `@react-router/node`, and `@react-router/serve`—combined with TypeScript and MobX for type-safe navigation and state management. This setup enables automatic route discovery, server-side rendering (SSR) for instant first paints, and reactive client-side navigation without full page reloads.

## File-Based Route Configuration

Plane adopts **file-based routing**, where the filesystem structure directly defines the application’s URL hierarchy. The route manifest lives in `apps/web/app/routes` and is automatically scanned by the React Router build toolchain.

### Route Definitions and Manifest Generation

Each route is a TypeScript file that exports route configuration objects, loaders, or actions. During the build process, `@react-router/dev` discovers these files and generates a route manifest in the `.react-router` folder. For example, authentication redirects are handled in dedicated route files:

- [`apps/web/app/routes/redirects/index.ts`](https://github.com/makeplane/plane/blob/main/apps/web/app/routes/redirects/index.ts) – Aggregates redirect route definitions
- [`apps/web/app/routes/redirects/core/signin.tsx`](https://github.com/makeplane/plane/blob/main/apps/web/app/routes/redirects/core/signin.tsx) – Uses React Router’s `redirect` helper to route unauthenticated users to the sign-in page

These files are fed into the router at runtime, creating a type-safe mapping between URLs and components.

## Router Configuration and Build Setup

The root configuration for Plane’s React Router application resides in **[`apps/web/react-router.config.ts`](https://github.com/makeplane/plane/blob/main/apps/web/react-router.config.ts)**. This configuration file defines the route file pattern and build options for both client and server bundles.

```ts
import type { Config } from "@react-router/dev/config";

export const config: Config = {
  routes: "app/routes/**/*.{tsx,ts}",
  // Additional options for asset handling and entry points
};

```

The Vite configuration in [`apps/web/vite.config.ts`](https://github.com/makeplane/plane/blob/main/apps/web/vite.config.ts) consumes this config through the `@react-router/dev` plugin. This integration handles:
- **Development**: Hot module replacement and fast refresh via `react-router dev`
- **Production**: Generation of client bundles (`.react-dir/client`) and server bundles (`.react-router/server`) for SSR

## Server-Side Rendering Architecture

Plane’s React Router implementation supports full **server-side rendering** to improve initial load performance and search engine visibility.

### Development vs. Production Rendering

During development, the command `pnpm dev` executes `react-router dev --port 3000`, which runs a specialized dev server using `@react-router/node`. This server renders routes on-demand for fast iteration. In production, the build process (`react-router build`) generates a static server bundle at [`build/server/index.js`](https://github.com/makeplane/plane/blob/main/build/server/index.js). The production server is launched using `react-router serve`, as configured in [`deployments/aio/community/supervisor.conf`](https://github.com/makeplane/plane/blob/main/deployments/aio/community/supervisor.conf), delivering pre-rendered HTML that hydrates into a dynamic React application on the client.

## Query Parameter Management with MobX

Plane synchronizes URL query parameters with application state through a dedicated **MobX store** called `RouterStore`. Located in [`apps/web/core/store/router.store.ts`](https://github.com/makeplane/plane/blob/main/apps/web/core/store/router.store.ts), this store parses the URL query string and exposes computed properties for common route parameters.

```ts
export class RouterStore implements IRouterStore {
  @observable query: ParsedUrlQuery = {};

  @action.bound setQuery(query: ParsedUrlQuery) {
    this.query = query;
  }

  @computed get workspaceSlug() {
    return this.query?.workspaceSlug?.toString();
  }

  @computed get projectId() {
    return this.query?.projectId?.toString();
  }

  @computed get issueId() {
    return this.query?.issueId?.toString();
  }
}

```

The framework calls `RouterStore.setQuery()` whenever the URL query string changes. Components observing `routerStore.workspaceSlug` or `routerStore.projectId` react automatically to navigation events without manually parsing `window.location`.

## Navigation Utilities and Query String Helpers

Plane provides utility functions for constructing navigation URLs. The **`generateQueryParams`** function in [`packages/utils/src/router.ts`](https://github.com/makeplane/plane/blob/main/packages/utils/src/router.ts) creates URL-encoded query strings while allowing specific keys to be excluded—useful when building filtered navigation links.

```ts
export const generateQueryParams = (
  searchParams: URLSearchParams,
  excludedParamKeys?: string[]
) => {
  const params = new URLSearchParams(searchParams);
  excludedParamKeys?.forEach((key) => params.delete(key));
  return params.toString();
};

```

This helper ensures consistent URL formatting across the application when programmatically generating navigation links or redirect URLs.

## Component-Level Router Integration

Components throughout Plane’s frontend import routing primitives directly from `react-router` to handle navigation, parameter extraction, and location awareness.

### Essential Hooks and Components

- **`useParams`** – Extracts dynamic route parameters such as `projectId` from URLs like `/projects/:projectId`
- **`useNavigate`** – Enables programmatic navigation after form submissions or user actions
- **`Link`** – Provides declarative navigation with prefetching capabilities
- **`useLocation`** – Accesses the current location object for breadcrumb generation or conditional UI rendering

### Practical Implementation Example

The following pattern appears in navigation components like [`apps/web/core/components/navigation/tab-navigation-root.tsx`](https://github.com/makeplane/plane/blob/main/apps/web/core/components/navigation/tab-navigation-root.tsx):

```tsx
import { Link, useNavigate, useParams, useLocation } from "react-router";

export const ProjectHeader = () => {
  const { projectId } = useParams();
  const navigate = useNavigate();
  const location = useLocation();

  const goToSettings = () => navigate(`/projects/${projectId}/settings`);

  return (
    <header>
      <Link to={`/projects/${projectId}`}>Back to Project</Link>
      <button onClick={goToSettings}>Settings</button>
      <span>Current path: {location.pathname}</span>
    </header>
  );
};

```

Similarly, modal components like [`apps/web/core/components/pages/modals/export-page-modal.tsx`](https://github.com/makeplane/plane/blob/main/apps/web/core/components/pages/modals/export-page-modal.tsx) use `useParams` to determine context-specific data without prop drilling.

## Runtime Navigation Flow

Understanding the React Router application’s runtime behavior reveals how Plane balances server performance with client interactivity:

1. **Initial Server Render** – When a user requests a URL, the server bundle ([`build/server/index.js`](https://github.com/makeplane/plane/blob/main/build/server/index.js)) executes the matching route’s loader, renders the component tree, and streams HTML to the browser.
2. **Client Hydration** – React Router’s client bundle takes over the static markup, attaching event listeners and initializing the `RouterStore` with the current URL state.
3. **Client-Side Navigation** – Clicking a `<Link>` intercepts the default browser behavior, updates the URL via the History API, fetches any necessary loader data, and re-renders only the changed route components.
4. **State Synchronization** – Query parameter changes trigger `RouterStore.setQuery()`, causing MobX observers to recalculate computed properties and update dependent UI elements reactively.

## Summary

- **File-based routing** in `apps/web/app/routes` automatically generates the route manifest through React Router v7’s build tools.
- **SSR configuration** in [`apps/web/react-router.config.ts`](https://github.com/makeplane/plane/blob/main/apps/web/react-router.config.ts) and [`vite.config.ts`](https://github.com/makeplane/plane/blob/main/vite.config.ts) enables both development hot-reloading and production server-side rendering via `@react-router/node`.
- **MobX integration** through [`apps/web/core/store/router.store.ts`](https://github.com/makeplane/plane/blob/main/apps/web/core/store/router.store.ts) provides reactive, computed access to URL parameters like `workspaceSlug` and `projectId`.
- **Utility functions** such as `generateQueryParams` in [`packages/utils/src/router.ts`](https://github.com/makeplane/plane/blob/main/packages/utils/src/router.ts) standardize query string manipulation across the codebase.
- **Component hooks** including `useParams`, `useNavigate`, and `Link` from `react-router` enable type-safe, declarative navigation patterns throughout the application.

## Frequently Asked Questions

### How does Plane handle server-side rendering with React Router?

Plane uses `@react-router/node` to render routes on the server during both development and production. In development, `react-router dev` provides a fast SSR dev server, while production builds generate a static server bundle at [`build/server/index.js`](https://github.com/makeplane/plane/blob/main/build/server/index.js) that is served by `react-router serve`. This approach delivers pre-rendered HTML for SEO and performance, which then hydrates into a fully interactive client-side application.

### What is the purpose of the RouterStore in Plane’s frontend?

The `RouterStore` in [`apps/web/core/store/router.store.ts`](https://github.com/makeplane/plane/blob/main/apps/web/core/store/router.store.ts) is a MobX store that parses the URL query string into reactive state. It exposes computed properties like `workspaceSlug`, `projectId`, and `issueId` that components can observe. When the URL changes, the framework calls `setQuery()`, automatically triggering updates in any component consuming these computed values without requiring manual URL parsing.

### How are routes defined in Plane’s React Router application?

Routes are defined using **file-based routing** in the `apps/web/app/routes` directory. Each `.tsx` or `.ts` file exports route configurations, loaders, or actions that React Router v7 discovers automatically based on the pattern defined in [`react-router.config.ts`](https://github.com/makeplane/plane/blob/main/react-router.config.ts). For example, [`apps/web/app/routes/redirects/core/signin.tsx`](https://github.com/makeplane/plane/blob/main/apps/web/app/routes/redirects/core/signin.tsx) handles authentication redirects using the `redirect` helper from React Router.

### What build tools does Plane use for its React Router implementation?

Plane uses **Vite** with the `@react-router/dev` plugin to handle the build process. The configuration in [`apps/web/vite.config.ts`](https://github.com/makeplane/plane/blob/main/apps/web/vite.config.ts) works alongside [`apps/web/react-router.config.ts`](https://github.com/makeplane/plane/blob/main/apps/web/react-router.config.ts) to generate client bundles for the browser and server bundles for SSR. The build outputs are stored in `.react-router/` during development and `build/` for production deployments.